C++电子课件(中)第七章.ppt
《C++电子课件(中)第七章.ppt》由会员分享,可在线阅读,更多相关《C++电子课件(中)第七章.ppt(120页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、C+电子课件电子课件(中中)第七第七章章7.1自由存储区内存分配自由存储区内存分配 7.4二叉树二叉树 (选读)(选读) 7.3 栈与队列的基本操作及其应用栈与队列的基本操作及其应用 7.2 链表与链表的基本操作链表与链表的基本操作 第七章第七章 动态内存分配与数据结构动态内存分配与数据结构7.17.1自由存储区内存分配自由存储区内存分配 7.1.1自由存储区自由存储区内存内存的分配与释放的分配与释放 7.1.2自由存储区自由存储区对象对象与构造函数与构造函数 7.1.3 浅复制与深复制浅复制与深复制 静态存储分配:静态存储分配:无论全局或局部变量无论全局或局部变量( (对象对象) ),编,编
2、译器在译器在编译时编译时都可以根据该变量都可以根据该变量( (对象对象) )的类型知道所需内存空间的类型知道所需内存空间的大小,从而系统在适当的时候的大小,从而系统在适当的时候为它们分配确定的存储空间。尤为它们分配确定的存储空间。尤其是数组。其是数组。动态存储分配:动态存储分配:有些操作对象只有在程序有些操作对象只有在程序运行时运行时才能确定,这样编译器在编译时才能确定,这样编译器在编译时就无法为他们预定存储空间,只就无法为他们预定存储空间,只能在程序运行时,系统根据运行能在程序运行时,系统根据运行时的要求进行内存分配,称为动时的要求进行内存分配,称为动态存储分配。动态分配都在态存储分配。动态
3、分配都在自由自由存储区存储区中进行。中进行。7.1.17.1.1自由存储区自由存储区内存的分配与释放内存的分配与释放当程序运行到需要动态分配变量或对象时,必须向系统当程序运行到需要动态分配变量或对象时,必须向系统申请申请取得自由存储区取得自由存储区中的一块所需大小的存贮空间,用于存贮该变中的一块所需大小的存贮空间,用于存贮该变量或对象。当不再使用该变量或对象时,也就是它的生命结束量或对象。当不再使用该变量或对象时,也就是它的生命结束时,要时,要显式释放显式释放它所占用的存贮空间,这样系统就能进行再次它所占用的存贮空间,这样系统就能进行再次分配,做到重复使用有限的资源。分配,做到重复使用有限的资
4、源。 申请和释放申请和释放自由存储区自由存储区中分配的存贮空间,分别使用中分配的存贮空间,分别使用newnew和和deletedelete的两个运算符来完成,其使用的格式如下:的两个运算符来完成,其使用的格式如下:指针变量名指针变量名=new 类型名类型名(初始化式初始化式);delete 指针名指针名;newnew运算符运算符返回返回的是一个指向所分配类型变量(对象)的的是一个指向所分配类型变量(对象)的指针指针。对所创建的变量或对象,都是通过该指针来间接操作的,。对所创建的变量或对象,都是通过该指针来间接操作的,而而动态创建的对象本身没有名字。动态创建的对象本身没有名字。 动态分配与释放:
5、动态分配与释放: 7.1.17.1.1自由存储区自由存储区内存的分配与释放内存的分配与释放一般定义变量和对象时要用标识符命名,称一般定义变量和对象时要用标识符命名,称命名对象命名对象,而动,而动态的称态的称无名对象无名对象( (请注意与栈区中的临时对象的区别,两者完请注意与栈区中的临时对象的区别,两者完全不同:生命期不同,操作方法不同,临时变量对程序员是全不同:生命期不同,操作方法不同,临时变量对程序员是透明的透明的) )。自由存储区自由存储区是不会自动在分配时做初始化的(包括是不会自动在分配时做初始化的(包括清零),所以必须用初始化式清零),所以必须用初始化式(initializer)(in
6、itializer)来显式初始化。来显式初始化。newnew表达式的操作:表达式的操作:从自由存储区分配对象,然后用括号中的值初始化该对象从自由存储区分配对象,然后用括号中的值初始化该对象。分配对象时,分配对象时,new表达式调用库操作符表达式调用库操作符new(): int *pi=new int(0);pi现在所指向的变量的存储空间是由库操作符现在所指向的变量的存储空间是由库操作符new()分配的,分配的,位于程序的自由存储区中,并且该对象未命名。位于程序的自由存储区中,并且该对象未命名。 无名对象:无名对象: 7.1.17.1.1自由存储区自由存储区内存的分配与释放内存的分配与释放自由存
7、储区自由存储区i演示:演示:用初始化式用初始化式(initializer)(initializer)来显式初始化来显式初始化 int *pi=new int(0);当当pipi生命周期结束时,生命周期结束时,必须释放必须释放pipi所指向的目标:所指向的目标: delete pi;注意这时释放了注意这时释放了pipi所指的目标的内存空间,也就是撤销了所指的目标的内存空间,也就是撤销了该目标,称动态内存释放(该目标,称动态内存释放(dynamic memory dynamic memory deallocationdeallocation),但),但指针指针pipi本身并没有撤销本身并没有撤销,
8、该指针所占,该指针所占内存空间并未释放。内存空间并未释放。 7.1.17.1.1自由存储区自由存储区内存的分配与释放内存的分配与释放数组动态分配格式:数组动态分配格式:指针变量名指针变量名=new 类型名类型名下标表达式下标表达式;delete 指向该数组的指针变量名指向该数组的指针变量名;说明:说明:两式中的两式中的方括号方括号必须配对使用。必须配对使用。如果如果delete语句中少了方括号,因编译器认为该指针是指语句中少了方括号,因编译器认为该指针是指向数组第一个元素的指针,会产生向数组第一个元素的指针,会产生回收不彻底回收不彻底的问题(的问题(只只回收了第一个元素所占空间回收了第一个元素
9、所占空间),),加了方括号后就转化为指加了方括号后就转化为指向数组的指针,回收整个数组向数组的指针,回收整个数组。 delete 的方括号中的方括号中不需要不需要填填数组元素数数组元素数,系统自知。,系统自知。即使写了,编译器也忽略。即使写了,编译器也忽略。 请注意请注意“下标表达式下标表达式”不是常量表达式不是常量表达式,即它,即它的值不必在编译时确定,的值不必在编译时确定,可以在运行时确定可以在运行时确定。7.1.17.1.1自由存储区自由存储区内存的分配与释放内存的分配与释放动态分配数组与动态分配数组与标准字符串类标准字符串类: 标准字符串类标准字符串类string就是采用动态建立数组的
10、方式解决就是采用动态建立数组的方式解决数组溢出的问题的,例数组溢出的问题的,例7.1所做的动态内存分配与释放,所做的动态内存分配与释放,在在string类对象中都是自动完成的,在程序中不需要也不类对象中都是自动完成的,在程序中不需要也不允许再显式地为允许再显式地为string进行动态内存的分配与释放。进行动态内存的分配与释放。【例【例7.1】动态数组的建立与撤销】动态数组的建立与撤销7.1.17.1.1自由存储区自由存储区内存的分配与释放内存的分配与释放动态分配数组的特点:动态分配数组的特点:1. 变量变量n在编译时没有确定的值,而是在运行中输入,在编译时没有确定的值,而是在运行中输入,按运行
11、按运行时所需分配空间时所需分配空间,这一点是动态分配的优点,可克服数组,这一点是动态分配的优点,可克服数组“大开小用大开小用”的弊端,在表、排序与查找中的算法,若用的弊端,在表、排序与查找中的算法,若用动态数组,通用性更佳。动态数组,通用性更佳。delete pc是将是将n个字符的空间个字符的空间释放,而用释放,而用delete pc则只释放了一个字符的空间;则只释放了一个字符的空间;2. 如果有如果有char *pc1,令,令pc1=pc,同样可用,同样可用delete pc1 来释放该空间。尽管来释放该空间。尽管C+不对数组作边界检查,但不对数组作边界检查,但在自由在自由 存储区存储区 空
12、间分配时,对数组分配空间大小是纪录在案的空间分配时,对数组分配空间大小是纪录在案的。3. 没有初始化式(没有初始化式(initializer),),不可对数组初始化不可对数组初始化。 7.1.17.1.1自由存储区自由存储区内存的分配与释放内存的分配与释放(选读)(选读)多维数组动态分配:多维数组动态分配:new 类型名类型名下标表达式下标表达式1 下标表达式下标表达式2;建立一个动态三维数组建立一个动态三维数组float (*cp)3020 ; /指向一个指向一个30行行20列数组的指针列数组的指针cp=new float 15 30 20; /建立由建立由15个个30*20数组组成的数组;
13、数组组成的数组;注意注意cp等效于三维数组名,但没有指出其边界,即等效于三维数组名,但没有指出其边界,即最高维的元素数量,就像指向字符的指针即等效一最高维的元素数量,就像指向字符的指针即等效一个字符串个字符串,不要把指向字符的指针,说成指向字符串不要把指向字符的指针,说成指向字符串的指针的指针。这与数组的嵌套定义相一致。这与数组的嵌套定义相一致。7.1.17.1.1自由存储区自由存储区内存的分配与释放内存的分配与释放(选读)(选读)比较:比较:float(*cp) 30 20; /三级指针三级指针float (*bp) 20; /二级指针二级指针cp=new float 1 30 20;bp=
14、new float 30 20;两个数组都是由两个数组都是由600个浮点数组成,前者是只有个浮点数组成,前者是只有一个元素一个元素的三维数组的三维数组,每个元素为,每个元素为30行行20列的二维数组,而另一列的二维数组,而另一个是有个是有30个元素的二维数组个元素的二维数组,每个元素为,每个元素为20个元素的一个元素的一维数组。维数组。删除这两个动态数组可用下式:删除这两个动态数组可用下式:delete cp; /删除(释放)三维数组删除(释放)三维数组delete bp; /删除(释放)二维数组删除(释放)二维数组【例【例7.2】 动态创建和删除一个动态创建和删除一个m*n个元素的数组个元素
15、的数组7.1.17.1.1自由存储区自由存储区的分配与释放的分配与释放指针使用的要点:指针使用的要点:1. 动态分配失败动态分配失败。返回一个空指针(。返回一个空指针(NULL),表示发生了异),表示发生了异常,堆资源不足,分配失败。常,堆资源不足,分配失败。2. 指针删除与自由存储区空间释放指针删除与自由存储区空间释放。删除一个指针。删除一个指针p(delete p;)实际意思是删除了)实际意思是删除了p所指的目标(变量或对象等),释所指的目标(变量或对象等),释放了它所占的自由存储区空间,而不是删除本身,释放自放了它所占的自由存储区空间,而不是删除本身,释放自由存储区空间后,成了空悬指针。
16、空悬指针是程序错误的由存储区空间后,成了空悬指针。空悬指针是程序错误的一个根源)。建议这时将置空(一个根源)。建议这时将置空(NULL)。)。3. new()和和delete()是可以重载的是可以重载的,它们都是类的静态成员函,它们都是类的静态成员函数。程序员无需显式声明它为静态的,系统自动定义为静态数。程序员无需显式声明它为静态的,系统自动定义为静态的。本教材不讨论的。本教材不讨论new()和和delete()的重载。未重载时,调用的重载。未重载时,调用全局库操作符全局库操作符new()。7.1.17.1.1自由存储区自由存储区内存的分配与释放内存的分配与释放4内存泄漏(内存泄漏(memor
17、y leak)和重复释放)和重复释放。new与与delete 是配对使用的,是配对使用的, delete只能释放只能释放自由存储区自由存储区空间。空间。如果如果new返回的指针值丢失,则所分配的返回的指针值丢失,则所分配的自由存储区自由存储区空间空间无法回收,称内存泄漏,同一空间重复释放也是危险的,无法回收,称内存泄漏,同一空间重复释放也是危险的,因为因为该空间可能已另分配该空间可能已另分配,所以必须妥善保存,所以必须妥善保存new返回的返回的指针,以保证不发生内存泄漏,也必须保证不会重复释放指针,以保证不发生内存泄漏,也必须保证不会重复释放自由存储区自由存储区内存空间。内存空间。5动态分配的
18、变量或对象的生命期动态分配的变量或对象的生命期。无名对象的生命期无名对象的生命期并不依赖于建立它的作用域,比如在函数中建立的动态对并不依赖于建立它的作用域,比如在函数中建立的动态对象在函数返回后仍可使用象在函数返回后仍可使用。但必须记住释放该对象所占自。但必须记住释放该对象所占自由存储区空间,并只能释放一次,在函数内建立,而在函由存储区空间,并只能释放一次,在函数内建立,而在函数外释放是一件很容易数外释放是一件很容易失控失控的事,往往会出错。的事,往往会出错。 7.1.27.1.2自由存储区自由存储区对象与构造函数对象与构造函数 类对象动态建立与删除过程:类对象动态建立与删除过程:通过通过ne
19、w建立的对象要调用构造函数,通过建立的对象要调用构造函数,通过delete删除对删除对象也要调用析构函数。象也要调用析构函数。CGoods *pc;pc=new CGoods; /分配自由存储区空间,并构造一个无名的分配自由存储区空间,并构造一个无名的CGoods对象;对象;.delete pc; /先析构,然后将内存空间返回给自由存储区;先析构,然后将内存空间返回给自由存储区;自由存储区自由存储区对象的生命期并不依赖于建立它的作用域,所以对象的生命期并不依赖于建立它的作用域,所以除非程序结束,除非程序结束,自由存储区自由存储区对象(无名对象)的生命期不会对象(无名对象)的生命期不会到期,并且
20、需要显式地用到期,并且需要显式地用delete语句析构该类对象,上例执语句析构该类对象,上例执行行delete语句时,语句时,C+自动调用商品类的析构函数。自动调用商品类的析构函数。7.1.27.1.2自由存储区自由存储区对象与构造函数对象与构造函数由自由存储区创建对象数组,只能调用默认由自由存储区创建对象数组,只能调用默认的构造函数,不能调用其他任何构造函数。如果的构造函数,不能调用其他任何构造函数。如果没有默认的构造函数,则不能创建对象数组。没有默认的构造函数,则不能创建对象数组。类对象初始化:类对象初始化:new后面类(后面类(class)类型可以有参数。这些参数即构造函数的)类型可以有
21、参数。这些参数即构造函数的参数。但对参数。但对创建数组创建数组,则无参数,则无参数,只能调用默认的构造函数只能调用默认的构造函数。【例【例7.37.3】演示自由存储区对象分配和释放。】演示自由存储区对象分配和释放。7.1.3浅复制与深复制浅复制与深复制 浅复制:浅复制:默认复制构造函数默认复制构造函数,可用一个类对象,可用一个类对象初始化另一个类对象,称为默认的初始化另一个类对象,称为默认的按成员复制,按成员复制,而不是而不是对整个类对象的对整个类对象的按位复制。按位复制。这称为这称为浅复制。浅复制。 图图7.1 浅复制浅复制 P自 由 存自 由 存储 区 对储 区 对象象自 由 存自 由 存
22、储 区储 区 对对象象PP 复制前复制前复制后复制后 如果类中有一个数据成员为指针,该类的一个对象如果类中有一个数据成员为指针,该类的一个对象obj1中中的这个指针的这个指针p,指向了动态分配的一个自由存储区对象,(参见,指向了动态分配的一个自由存储区对象,(参见图图7.1复制前),如果用复制前),如果用obj1按成员复制了一个对象按成员复制了一个对象obj2,这时,这时obj2.p也指向同一个自由存储区对象。也指向同一个自由存储区对象。obj1obj1obj27.1.3浅复制与深复制复制浅复制与深复制复制当当浅复制浅复制析构时,如用默认的析构析构时,如用默认的析构函数,则动态分配的函数,则动
23、态分配的自由存储区自由存储区对象不对象不能回收。如果在析构函数中有能回收。如果在析构函数中有“delete p;”语句,则如果先析构函数语句,则如果先析构函数obj1时,时,自由存储区自由存储区对象已经释放,以后再析构对象已经释放,以后再析构obj2时出现了二次释放的问题。时出现了二次释放的问题。自由自由存储存储区区对对象象PP自由自由存储存储区区对对象象 图图7.2 深复制深复制 深复制:深复制:重新定义复制的构造函数,重新定义复制的构造函数,给每个对象独立分配一个自由存储区给每个对象独立分配一个自由存储区对象,称对象,称深复制深复制。这时先复制对象主这时先复制对象主体,再为体,再为obj2
24、分配一个自由存储区对分配一个自由存储区对象,最后用象,最后用obj1的自由存储区对象复的自由存储区对象复制制obj2的自由存储区对象。的自由存储区对象。 obj1obj27.1.3浅复制与深复制浅复制与深复制【例【例7.4】定义复制构造函数定义复制构造函数 (copy structor)和复制赋值操)和复制赋值操作符(作符(copy Assignment Operator)实现深复制。)实现深复制。 学生类定义:学生类定义:class student char *pName; /为了演示深复制,不用为了演示深复制,不用string类类public: student(); /默认构造函数默认构造
25、函数 student(char *pname); /带参数构造函数带参数构造函数 student(student &s); /复制构造函数复制构造函数 student(); /析构函数析构函数 student & operator=(student &s); ; /复制赋值操作符复制赋值操作符检验主函数和运行结果检验主函数和运行结果7.1.3浅复制与深复制浅复制与深复制 提示:提示: 自由存储区内存是最常见的需要自定义复制构自由存储区内存是最常见的需要自定义复制构造函数的资源,但不是唯一的,还有打开文件等也造函数的资源,但不是唯一的,还有打开文件等也需要自定义复制构造函数。需要自定义复制构造函
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- C+ 电子 课件 第七
限制150内