1、指针和自由存储空间
1.1 什么是指针?
首先,我们如何找到一个变量的地址呢?只需对变量应用地址运算符(&),就可以得到它的地址。比如说,num是一个变量,&num就是它的地址。
指针就是一种特殊类型的变量,它用来存储值的地址。因此,指针名表示的是地址。*运算符被称为解除引用运算符,将其用于指针,可以得到该地址存储的值。假设p_cat是一个指针,则p_cat是一个地址,而*p_cat表示存储在该地址处的值。*p_cat与常规int变量等效。下面的程序演示了如何声明指针:
#include<iostream>
using namespace std;
int main()
{
int num = 6;
int * p_num;
p_num = #
}
int变量num和指针变量p_num只不过是同一枚硬币的两面。 变量num表示值, 并使用&运算符来获得地址; 而变量p_num表示地址, 并使用 *运算符来获得值。由于 p_num指向num,因此*p_num和 num完全等价。 可以像使用int变量那样使用 *p_num。 甚至可以将值赋给*p_num,这样将修改指向的值。
1.2 指针的危险
在C++创建指针时,计算机将分配用来存储地址的内存,但不会分配用来存储指针所指向数据的内存!如下程序所示:
long * fellow;
*fellow = 223300;
其中,fellow确实是一个指针,但上述代码没有将地址赋给fellow,所以我们不知道它指向哪里。 我们也就不知道223300将被放在哪里。 由于fellow没有被初始化, 它可能有任何值。 不管值是什么, 程序都将它解释为存储 223300的地址。 如果fellow的值碰巧为 1200, 计算机将把数据放在地址1200上, 即使这恰巧是程序代码的地址。fellow指向的地方很可能并不是所要存储 223300的地方。 这种错误可能会导致一些最隐匿、 最难找的bug。
注意:一定要在对指针应用解除引用符(*)之前,将指针初始化为一个确定的、适当的地址!
2、使用new来分配内存
我们将指针初始化为变量的地址,变量是在编译时分配的有名称的内存, 而指针只是为可以通过名称直接访问的内存提供一个别名。指针真正的用武之地在于, 在运行阶段分配未命名的内存以存储值。 在这种情况下,只能通过指针来访问内存。C语言中,可以用库函数 malloc()来分配内存,C++也可以这样做,也可以用new运算符。
程序员要告诉 new, 需要为哪种数据类型分配内存; new将找到—个长度正确的内存块, 并返回该内存块的地址。 如下示例:
int * pn = new int;
new int告诉程序,需要适合存储int的内存。 new运算符根据类型来确定需要多少字节的内存。 然后,它找到这样的内存,并返回其地址。 接下来, 将地址赋给pn, pn是被声明为指向int的指针。 pn是地址, 而*pn是存储在那里的值.
为一个数据对象分配内存的通用格式如下:
typeName * pointer_name = new typeName;
对于指针,new分配的内存块通常与常规变量声明分配的内存块不同。常规变量都存储在被称为栈(stack) 的内存区域中, 而new从被称为堆(heap ) 或自由存储区(freestore) 的内存区域分配内存。
在C++中,值为0的指针被称为空指针(nullpointer)。C++确保空指针不会指向有效的数据,因此它常被用来表示运算符或函数失败(如果成功, 它们将返回一个有用的指针)。
3、使用delete释放内存
当需要内存时, 可以使用new来请求, delete运算符使得在使用完内存后, 能够将其归还给内存池,归还或释放(free)的内存可供程序的其他部分使用。使用delete时, 后面要加上指向内存块的指针。
int * ps = new int;
...
delete ps;
注意:new和delete要配对使用;只能用delete来释放使用new分配的内存;对空指针使用delete是安全的;
4、使用new来创建动态数组
通常, 对于大型数据(如数组、字符串和结构), 应使用new, 这正是new的用武之地。例如, 假设要编写一个程序, 它是否需要数组取决于运行时用户提供的信息。如果通过声明来创建数组, 则在程序被编译时将为它分配内存空间。不管程序最终是否使用数组, 数组都在那里, 它占用了内存。在编译时给数组分配内存被称为静态联编(static binding), 意味着数组是在编译时加入到程序中的。但使用new时,如果在运行阶段需要数组,则创建它;如果不需要,则不创建。还可以在程序运行时选择数组的长度。这被称为动态联编(dynamicbinding),意味着数组是在程序运行时创建的。这种数组叫作动态数组(dynamicarray)。使用静态联编时,必须在编写程序时指定数组的长度:使用动态联编时,程序将在运行时确定数组的长度。
4.1 使用new创建动态数组
在C++中, 创建动态数组很容易;只要将数组的元素类型和元素数目告诉new 即可。必须在类型名后加上方括号, 其中包含元素数目。例如, 要创建一个包含10个int 元素的数组, 可以这样写:
int * psome = new int[10];
new 运算符返回第一个元素的地址。 该地址被赋给指针psome。
当程序使用完new 分配的内存块时, 应使用delete 释放它们。然而, 对于使用new 创建的数组, 应使用另一种格式的delete 来释放:delete [] some;
注意,使用new 和delete 时, 应遵守以下规则:
- 不要使用delete 来释放不是new 分配的内存。
- 不要使用delete 释放同一个内存块两次。
- 如果使用new[ ]为数组分配内存, 则应使用delete[ ]来释放。
- 如果使用new[ ]为一个实体分配内存, 则应使用delete (没有方括号)来释放。
- 对空指针应用delete 是安全的。
4.2 使用动态数组
如何使用动态数字呢?第一个元素不成问题,psome就指向数组的第一个元素,那么其它9个元素呢?其实很简单,将指针当作数组名使用即可。也就是说,第一个元素:psome[0],第二个元素:psome[1]...
5、小结
5.1 声明指针
typeName * pointerName;
5.2 给指针赋值
应将内存地址赋给指针。 可以对变量名应用&运算符来获得被命名的内存的地址, new 运算符返回未命名的内存的地址。
5.3 对指针解除引用
对指针解除引用意味着获得指针指向的值。对指针应用解除引用或间接值运算符(*)来解除引用。
5.4 指针算术
C++允许将指针和整数相加。加1的结果等于原来的地址值加上指向的对象占用的总字节数。 还可以将一个指针减去另一个指针, 获得两个指针的差。这种运算将得到一个整数,仅当两个指针指向同一个数组(也可以指向超出结尾的一个位置) 时,这种运算才有意义,这将得到两个元素的间隔。
5.5 数组的动态联编和静态联编
使用数组声明来创建数组时,将采用静态联编, 即数组的长度在编译时设置;使用 new运算符创建数组时,将采用动态联编(动态数组),即在程序运行时为数组分配空间, 其长度也将在运行时设置。使用完这种数组后, 应使用delete []释放其占用的内存。
----参考 C++ Primer Plus 第六版

908

被折叠的 条评论
为什么被折叠?



