到目前为止,程序中用于存储数据的变量和数组等实体在使用前都必须通过声明语句进行定义。C++编译器根据这些声明语句了解它们所需存储空间的大小,并预先为其分配适当的内存空间。也就是说,这些变量或数组在内存中所占据的空间大小必须在编译时(即程序运行前)确定下来,这种内存分配方式称为“静态存储分配”。
但是在很多情况下,程序中所需的内存数量只有等到运行时刻才能确定下来。例如,需要在程序运行期间根据用户提供的输入信息决定分配存储空间的大小。这时就应使用“动态存储分配”方式申请获得指定大小的内存空间;当动态分配的内存空间闲置不用时同样有必要对其进行释放。动态存储分配功能在C++中是通过new和delete运算符来实现的。
》使用new获得动态内存空间
运算符new用于申请动态存储空间,它的操作数为某种数据类型且可以带有初值表达式或元素个数。new返回一个指向其操作数类型变量的指针。使用new对某种类型变量进行动态分配的语法格式为:
<指针>=new<类型>; 例:int* pi=new int;
其中,<类型>表示要分配的变量类型(如char、int、double等);<指针>表示指向<类型>类型变量的指针(如char*、int*、double*等)。例中动态分配了一个int型变量,并将此变量的地址赋值给int型指针pi。如果需要在分配变量的同时为其赋初值,则可以在类型之后加上初值表达式(放在圆括号内)
int* pi=new int(3); 表示不仅动态地分配了一个int型变量而且将其初值初始化为3.
运算符new还可以用来对数组进行动态分配,这时需要在数据类型后面添加方括号[ ],并在其中指明所要分配的数组元素个数。
语法:<指针>=new <类型>[<元素个数>]; 例:int* pia=new int[10];
其中<类型>表示数组元素的数据类型;<指针>表示指向<类型>元素的指针;<元素个数>是一个表达式,用于表示需要动态分配的数组元素个数。例中为含有10个元素的int型数组进行动态存储分配,然后把该数组的首元素地址赋给指针pia。此时pia指向内存中的一片可以容纳10个int型元素的连续存储空间。
注:new运算符没有提供对动态分配的数组进行初始化的语法结构。
使用new动态分配的数组与一般定义语句声明的数组之间的最大区别是,前者的元素个数可以是一个变量,而后者的元素个数必须是常量。这就意味着动态存储分配能够在程序运行时根据实际需要指定数组元素的个数。
用于动态分配的内存空间又称为堆内存(Heap)或自由存储区(Free store),它通常由操作系统管理且数量有限,因此如果在程序中不断地分配堆内存就有可能将其耗尽。在这种情况下,系统无法再对new提出堆内存分配请求给予满足,此时new会返回空指针NULL,表示动态存储分配操作失败。建议程序员在执行动态存储分配之后务必检查一下new返回的指针是否为空;如果为空,则须采取必要的措施(如输出提示信息并退出程序),以免后续代码使用空指针而产生错误。
》使用delete释放动态内存空间
当动态分配的内存空间在程序中使用完毕之后,必须显示地将它们释放。这样做的目的是把闲置不用的堆内存归还给系统,使其可以被系统重新分配。在C++程序中由new分配的动态内存空间必须通过delete运算符释放。
语法格式为: delete<指针>; 其中,<指针>表示指向单个变量的指针。
对数组进行释放的语法格式: delete [ ]<指针>;
其中,<指针>表示指向数组首元素的指针。delete之后的方括号指明将要释放的内存空间中存储着数组元素。
注:上述指针必须是由new返回的指向动态分配内存空间的地址,而不能是普通变量或数组元素,否则会产生十分眼中的错误。new与delete在程序中总是成对的出现。