动态内存管理
动态对象(堆对象)是程序在运行过程中在动态内存中用new运算符创建的对象。
由于是用户自己用new运算符创建的,因此也要求用户自己用delete运算符释放,即用户必须自己管理动态内存。
计算机内存数据区常有三种分区,即静态数据区、堆区、桟区。
1.程序在编译时就为静态变量和静态对象分配了静态数据存储区。在静态数据区中存储的变量或对象在该程序的整个运行期间都存在,
它们的生命周期贯穿整个程序的运行周期。比如全局变量、static(静态)变量等都是存储在静态数据区。
2.调用函数时,函数内的局部变量和形式参数等将在桟区中分配存储单元。这部分变量的生命周期与函数的执行时间相同。
当函数执行结束时,存储这些变量的存储单元会被自动释放,从而这些变量的生命周期也就结束了。
由于桟区的大小一般很有限,因此能够同时保存在桟区中的变量数量有限。
由于存储在桟区中的变量生命周期短,因此桟区的使用率高很高,可以不断成为新生成变量的存放空间。
3.当执行new运算符时,系统会自动在动态内存空间中分配存储,动态内存位于堆区,它是唯一一个生存期可以由程序员自己控制的存储空间。
程序在运行时程序员可以用new申请动态内存空间,但不用时,程序员必须自己用delete释放这部分空间(释放内存)。
因此,程序在这部分出错的概率极高。
管理动态内存空间的运算符是new和delete,还有new[]与delete[].
C语言中用 malloc()和free()函数申请分配和释放动态内存空间。
C++用new和delete运算符来申请分配和释放动态内存空间。
new运算符可以自动计算所申请空间的大小,而malloc()函数则必须由程序员指出所需申请分配空间的大小。
#include<iostream> using namespace std; int main() { char *p1; int *p2; int *p3=new int (14); int *p4=new int [3]; p1=new char; //new一个整型数,并将该整型数的地址赋值给p1 p2=new int (10);//new一个初值为200的整型数,并将该整型数的地址赋给p2 *p1=97; for(int i=0;i<3;i++) { cin>>*(p4+i); } cout<<*p1<<endl; cout<<*p2<<endl; cout<<*p3<<endl; for(int i=0;i<3;i++) { cout<<*(p4+i)<<" "; } cout<<endl; delete p3; delete p2; delete p1; delete []p4; p1=NULL; p2=NULL; p3=NULL; p4=NULL; system("pause"); return 0; }
注意:
1.当系统无法满足动态内存分配的请求时他将会返回NULL,所以new执行后必须判断返回的指针值是否为NULL,是则表示动态内存分配不成功。
只有返回值是非NULL时,才可继续执行后续的操作。
如果对一个,一申请成功的指针进行相关的内存操作将可能引起系统崩溃。
2.delete只能用来释放用new申请分配的动态内存空间;反之,new申请的动态内存空间必须用delete来释放。
delete与new必须有对应的关系。
3.delete执行之后,指针所指向的内存空间就被释放了,而指向该动态内存区域的指针变量本身并不会因为delete有任何改变。
4.delete之后,不对指针变量做任何处理,就会造成“指针悬挂”;
5.指针变量声明后没有进行初始化就通过它操作内存空间,则可能制造一个“野指针”;
6.关于指针和动态内存要特别注意:
指针消亡了,并不代表它所指向的动态内存会被自动释放,自动消亡;
动态内存被释放了,并不代表指向该动态内存的指针变量会消亡或自动变成NULL;
做到以下几点:
1.定义指针变量的同时初始化。如不初始化就一定要将其设置成NULL,避免该指针指向一个不确定的地方,引发误操作,这是非常危险的。
一旦把它置成NULL,误用它就不会造成太大问题;
2.delete指针以后,第一时间将其设置为NULL。即使是一个马上就要消亡的局部指针变量,也可立即将其置成NULL。养成良好的习惯是避免错误的有效方法;
3.当指针指向数组时,一定谨慎防止指针越界操作;
4.避免用指针传递桟内存,避免返回一个即将自动消亡的局部变量或局部对象的地址。
桟内存中的局部变量和局部对象都不能跨函数生存,要注意它们的生存周期。