《C动态内存分配与引用.ppt》由会员分享,可在线阅读,更多相关《C动态内存分配与引用.ppt(23页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、1对于计算机程序设计而言,变量和对象在内存中的分配都是编译器在编译程序时安排好的,这带来了极大的不便,如数组必须大开小用,指针必须指向一个已经存在的变量或对象。对于不能确定需要占用多少内存的情况,动态内存分配解决了这个问题。C/C+定义了4个内存区间:代码区,全局数据区,栈区,堆(heap)区。2通常定义变量时,编译器在编译时根据该变量的类型,在适当的时候为他们分配所需的内存空间大小。这种内存分配称为静态存储分配。但有些操作只有在程序运行时才能确定,这样编译器在编译时就无法为他们预定存储空间,只能在程序运行时,系统根据运行时的要求进行内存分配,这种方法称为动态存储分配。所有动态存储分配都在堆区
2、中进行。3全局变量全局变量静态数据静态数据常量常量函数函数 函数运行函数运行时分配的时分配的局部变量、局部变量、函数参数、函数参数、返回数据、返回数据、返回地址返回地址等等内存中剩余的内存中剩余的空间由程序员空间由程序员负责申请和释负责申请和释放在放在C+里堆里堆空间的申请和空间的申请和释放分别用到释放分别用到操作符:操作符:new 和和 delete全局数据区全局数据区data area代码区代码区code area栈区栈区stack area堆区堆区heap area4 当当程程序序运运行行到到需需要要一一个个动动态态分分配配的的变变量量或或对对象象时时,必必须须向向系系统统申申请请取取得
3、得堆堆区区中中的的一一块块所所需需大小的存储空间,用于存储该变量或对象。大小的存储空间,用于存储该变量或对象。当当不不再再使使用用该该变变量量或或对对象象时时,也也就就是是它它的的生生命命结结束束时时,要要显显式式释释放放它它所所占占用用的的存存储储空空间间,这这样样系系统统就就能能对对该该堆堆空空间间进进行行再再次次分分配配,做做到到重复使用有限的资源。重复使用有限的资源。在C+中,申请和释放堆中分配的存储空间,分别使用new和delete这两个运算符来完成,其使用的格式如下:指针变量名=new 类型名(初始值);delete 指针名;new运算符返回的是一个指向所分配类型变量(对象)的指针
4、。对所创建的变量或对象,都是通过该指针来间接操作的,而动态创建的对象本身没有标识符名。6u一般定义变量和对象时要用标识符命名,称一般定义变量和对象时要用标识符命名,称命命名对象名对象,而动态的称,而动态的称无名对象无名对象。unewnew表达式的操作序列如下:表达式的操作序列如下:从堆区分配对象,从堆区分配对象,然后用括号中的值初始化该对象然后用括号中的值初始化该对象。从堆区分配对。从堆区分配对象时,象时,newnew表达式调用库操作符表达式调用库操作符new()new()。例如:。例如:int*pi=new int(0);int*pi=new int(0);说明:说明:pipi现在所指向的变
5、量是由库操作符现在所指向的变量是由库操作符newnew()()分配的,位于程序的堆区中,并且该分配的,位于程序的堆区中,并且该对象对象未命名未命名。堆堆i下面看演示:下面看演示:用初始化式用初始化式(initializer)(initializer)来显式初始化来显式初始化 int*pi=new int(0);int*pi=new int(0);当当pipi生命周期结束时,生命周期结束时,必须释放必须释放pipi所指向的目标:所指向的目标:delete pi;delete pi;注意这时释放了注意这时释放了pipi所指的目标的内存空间,也就是所指的目标的内存空间,也就是撤销了该目标,称动态内存
6、释放(撤销了该目标,称动态内存释放(dynamic memory dynamic memory deallocationdeallocation),但),但指针指针pipi本身并没有撤销本身并没有撤销,它自,它自己仍然存在,该指针所占内存空间并未释放。己仍然存在,该指针所占内存空间并未释放。使用new运算符时必须已知数据类型,new运算符会向系统堆区申请足够的存储空间,如果申请成功,就返回该内存块的首地址,如果申请不成功,则返回零值。一般格式格式1:指针变量名=new 类型标识符;格式2:指针变量名=new 类型标识符(初始值);格式3:指针变量名=new 类型标识符内存单元个数;说明:格式1
7、和格式2都是申请分配某一数据类型所占字节数的内存空间;但是格式2在内存分配成功后,同时将一初值存放到该内存单元中;而格式3可同时分配若干个内存单元,相当于形成一个动态数组。9【例91:利用new对变量进行分配空间】#include using namespace std;void main()char*pc;int*pi;pc=new char;pi=new int(8);*pc=a;coutpcendl;cout*piendl;/格式格式1 1/格式格式2 2输出结果:输出结果:输出结果:输出结果:a a 8 8a堆区堆区堆区堆区8pcpi栈区栈区栈区栈区1000100010011001如果
8、内存分配失败,则如果内存分配失败,则返回零值。所以在动态返回零值。所以在动态分配内存时,应对返回分配内存时,应对返回的指针进行检查的指针进行检查10/通过指针指向动态分配的内存的首地址通过指针指向动态分配的内存的首地址 对于数组进行动态分配的格式为:对于数组进行动态分配的格式为:指针变量名指针变量名=new=new 类型名类型名 下标表达式下标表达式;delete delete 指向该数组的指针变量名指向该数组的指针变量名;两式中的两式中的方括号方括号是非常重要的,两者必须配对使用,是非常重要的,两者必须配对使用,如果如果deletedelete语句中少了方括号,因编译器认为该指针语句中少了方
9、括号,因编译器认为该指针是指向数组第一个元素的指针,会产生是指向数组第一个元素的指针,会产生回收不彻底回收不彻底的的问题(问题(只回收了第一个元素所占空间只回收了第一个元素所占空间),),加了方括号加了方括号后就转化为指向数组的指针,回收整个数组后就转化为指向数组的指针,回收整个数组。delete delete 的方括号中的方括号中不需要不需要填填数组元素数数组元素数,系统自,系统自知。即使写了,编译器也忽略。知。即使写了,编译器也忽略。请注意请注意“下标表达式下标表达式”不是常量表达式不是常量表达式,即它的值不,即它的值不必在编译时确定,必在编译时确定,可以在运行时确定可以在运行时确定。【例
10、92:new 运算符为数组分配空间】void main()char*string=new char20;char str20;strcpy(string,It is a string.);strcpy(str,It is a string too.);coutstringendl;coutstrendl;问:内存区域中,栈区怎么变化?堆区怎么变化?12ItIt堆区堆区栈区栈区strstring13【例例9 93 3:动态数组的建立与撤销:动态数组的建立与撤销】void main()int n;char*pc;cout请输入动态数组的元素个数请输入动态数组的元素个数n;/在运行时确定,可输入在运
11、行时确定,可输入1717pc=new charn;/申请申请1717个字符(可装个字符(可装8 8个汉字和一个结束符)的内存空间个汉字和一个结束符)的内存空间strcpy(pc,堆内存的动态分配堆内存的动态分配);coutpcendl;delete pc;/释放释放pcpc所指向的所指向的n n个字符的内存空间个字符的内存空间使用new运算符分配的内存一定要释放,否则会产生系统内存泄漏。如:void main()char*pc;int*pi;pc=new char;pi=new int(8);*pc=a;coutpcendl;cout*piendl;15a8pcpi栈区栈区10001001当该
12、函数或者该程序执行完毕后系统弹栈,当该函数或者该程序执行完毕后系统弹栈,pc和和pi这两个变量将消失,但他们指向的这两个变量将消失,但他们指向的堆内的内存并不会自动释放,那么该内存堆内的内存并不会自动释放,那么该内存将再不能使用,除非系统重启将再不能使用,除非系统重启堆区堆区void main()char*pc=NULL;int*pi;pc=new char;pi=new int(8);*pc=a;coutpcendl;cout*piendl;if(pc)delete pc;if(pi)delete pi;17void main()void main()char*string=new char
13、20;char*string=new char20;if(string=0)return;char str20;strcpy(string,It is a string.);strcpy(str,It is a string too.);coutstringendl;coutstrendl;delete string;对对对对于于于于动动动动态态态态申申申申请请请请数数数数组组组组空空空空间间间间的的的的释释释释放放放放18ItIt堆区堆区栈区栈区strstring回收的空间回收的空间100010001920【例94】从键盘输入10个int型数,而后按输入的相反顺序输出它们。要求使用new运算
14、符动态申请数据空间存放数据。程序执行后的输入输出界面为:输入:1 2 3 4 5 6 7 8 9 10运行输出:10 9 8 7 6 5 4 3 2 1 21void main()int i,*a,*p;a=new int10;coutinput 10 integers:endl;for(i=0;i*(a+i);/也可用ai cout-The result-=a;p-)cout*p;coutendl;以变量形式分配内存比较死板。有了以变量形式分配内存比较死板。有了newnew和和delete,delete,就可就可以实现一种动态分配内存的形式,即通过指针引用,而以实现一种动态分配内存的形式,即
15、通过指针引用,而内存的分配和释放可以在程序的任何地方进行。内存的分配和释放可以在程序的任何地方进行。动态分配失败。动态分配失败。返回一个空指针(返回一个空指针(NULLNULL),),表示发生了异常,堆资源不足,分配失败。表示发生了异常,堆资源不足,分配失败。指针删除与堆空间释放。指针删除与堆空间释放。删除一个指针删除一个指针p p(delete p;delete p;)实际意思是删除了)实际意思是删除了p p所指的目标所指的目标(变量或对象等),释放了它所占的堆空间,(变量或对象等),释放了它所占的堆空间,而不是删除本身,释放堆空间后,成了而不是删除本身,释放堆空间后,成了空空指针指针。内存
16、泄漏(内存泄漏(memory leakmemory leak)和重复释放)和重复释放。newnew与与delete delete 是配对使用的,是配对使用的,deletedelete只能释放堆空间。如只能释放堆空间。如果果newnew返回的指针值丢失,则所分配的堆空间无法回收,返回的指针值丢失,则所分配的堆空间无法回收,称内存泄漏,同一空间重复释放也是危险的,因为称内存泄漏,同一空间重复释放也是危险的,因为该该空间可能已另分配空间可能已另分配,所以必须妥善保存,所以必须妥善保存newnew返回的指针,返回的指针,以保证不发生内存泄漏,也必须保证不会重复释放堆以保证不发生内存泄漏,也必须保证不会重复释放堆内存空间。内存空间。动态分配的变量或对象的生命期。动态分配的变量或对象的生命期。我们也称堆空我们也称堆空间为自由空间(间为自由空间(free storefree store),),但必须记住释放该对但必须记住释放该对象所占堆空间,并只能释放一次,在函数内建立,而象所占堆空间,并只能释放一次,在函数内建立,而在函数外释放,往往会出错。在函数外释放,往往会出错。