目录
7、指针和自由存储空间
计算机内存
- 计算机存储数据时必须的基本属性:信息存储在何处、值是多少、什么类型。
- 内存地址使用十六进制表示法,每个地址占1字节,8bit。
- 两个地址间相差4是因为存储类型为int,占用4个字节。
运行阶段
- 编译阶段:编译器将程序组合起来。声明数组必须指定数组长度,在编译阶段分配内存。
- 变量:在编译时分配的有名称的内存。
- 运行阶段:看情况判断,运行阶段决策。
指针
- 指针是一个变量,存储的值是地址,而不是值本身。
- 对常规变量采用地址运算符 & ,就可获得其位置。
- 运算符 * 称为间接值或解除引用运算符,用于指针可以得到该地址存储的值。
声明与初始化
- 指针声明必须指定指向的数据类型。
- 没有初始化的指针不知道信息存储在哪,可能改写内存中的信息。
- 声明时初始化
- 指针没有初始化,可能指向任何值。
- 一定要在使用 * 之前,将指针初始化为一个确定的地址
- 指针不是整型,两者截然不同,数值当做地址必须经过强制类型转换。
int* ptr = (int*) 0xB8000000;
分配内存 new
- 指针真正的用武之地在于,在运行阶段分配未命名的内存以存储值。
- 变量:在编译时分配的有名称的内存。
- 指针:直接访问内存的别名。
- C语言中采用库函数malloc()分配内存,C++采用new运算符。使程序在内存管理方面有更大的控制权。
- 通用格式: typeName* pointer_name = new typeName;
- new将找到一个长度正确的内存块,并返回其地址。
- pn的内存只能通过指针访问。
- new分配的内存块与常规变量分配的内存不同:普通变量值存储在栈(stack)内存中,new从堆(heap)或自由存储区域(free store)分配内存。
- C++中值为0的指针称为空指针(null pointer),不会指向有效的数据,用来表示运算符或函数失败。
释放内存delete
int* ptr = new int;
...
delete ptr;
- delete 用来释放new分配的内存,且只能用于new分配的内存。
- delete将释放ptr指向的内存,不会删除指针本身,可以将ptr指向新的内存。
- delete 和 new 一定要配对使用,否则会发生内存泄漏(memory leak)。
- 不要释放已经释放的内存块,否则什么情况都有可能发生。
- delete 不能用于声明变量的内存,可以用于空指针。
- 一般不要创建两个指向同一内存的指针。
new 创建动态数组
- 静态联编(static binding):在编译时给数组分配内存。如果通过声明创建数组,则在程序编译时分配内存,不管程序最终是否使用,都占用了内存。
- 动态联编(dynamic array):使用new创建动态数组:在运行阶段,如果使用则创建,不需要则不创建。
- 静态联编时在编写程序时指定数组长度,动态联编时在运行阶段确定数组长度。
int* psome = new int[10];
delete [] psome;
int* pt = new int;
delete pt;
- 在类型名后要声明包含的元素数目。
- new 运算符返回第一个元素的地址。
- 通用格式:type_name* pointer_name = new type_name [num_elements];
- delete[] 表示释放整个数组,不仅仅是指针指向的元素。
小结
- 不能使用sizeof运算符决定动态分配的数组包含的字节数。
访问动态数组
- ptr指向第一个元素double[0],*ptr是第一个元素的值。
- 访问元素只需将指针作为数组名使用即可。数组和指针基本等价是C和C++的优点之一。
double* ptr = new double[3];
ptr[0] = 0.2;
ptr[1] = 0.5;
ptr[2] = 0.8;
ptr = ptr + 1;
ptr = ptr - 1;
delete [] ptr;
- ptr = ptr + 1; 将指针指向第二个元素。
- 指针变量+1后,增加的值等于指向类型所占的字节数。
- delete时,要保证指针提供正确的首元素的地址。
8、指针、数组和指针运算术
- C++将数组名解释为数组第一个元素的地址。
- 特殊情况:对数组使用sizeof()得到的是数组长度(单位为字节);对指针sizeof()得到指针本身的长度。
- 特殊情况2:对数组取地址时,数组名不会被解释为地址。
- 对数组名取地址得到整个数组的地址。
指针和字符串
- 给cout提供一个字符的地址,将从该字符开始打印,直到空字符为止。
- 如果要打印字符串地址,需要将指针强转:cout << (int *) ptr;
- "wren"的地址赋值给指针bird,cons关键字,使得可以用bird访问字符串,但不能修改。
strncpy()
- strncpy(target, source, size);
- 第三个参数是,要复制的最大字符数。
- source长度小于size,复制后自动在结尾添加空字符。
- source长度大于size,不会添加空字符,需要手动置空。
9、类型组合
10、vector array
模板类vector
- 动态数组,可以在运行阶段改变vector对象长度
- 使用new 、delete自动管理内存
- #include <vector>
- using namespace std;
- vector<int> vi;
- vector<int> vi[n];
模板类array
- array 适合固定长度的数组,栈(静态内存分配)
- 比数组方便安全
- vector 功能强大,更方便安全,但,效率低
- #include <array>
- using namespace std;
- array<int, 4> ai;
- array<double, 3> ad = {1.2, 1.1, 1.3};
对比
- array对象 和 数组 存储在栈内存区域
- vector对象 存储在自由存储区或堆
- 可以将array对象赋值给另一array对象,数组不可以
- C++不检查超界错误,*(a1 - 2) = 2.2; 存储到数组外面。