计算机程序设计基础计算机程序设计基础计算机程序设计基础计算机程序设计基础教师:文迪教师:文迪Email: Email: wendi@tsinghua.edu.cnwendi@tsinghua.edu.cn清华大学电子工程系清华大学电子工程系清华大学电子工程系清华大学电子工程系智能图文信息处理实验室智能图文信息处理实验室回顾上节课内容回顾上节课内容回顾上节课内容回顾上节课内容1.1.结构体类型的定义结构体类型的定义1.1.结构体类型的定义结构体类型的定义2.2.结构体类型的变量结构体类型的变量33结构体与函数结构体与函数3.3.结构体与函数结构体与函数4.4.结构体数组结构体数组5.5.联合体和枚举类型联合体和枚举类型第十章第十章结构体和联合体(二)结构体和联合体(二)第十章第十章结构体和联合体(二)结构体和联合体(二)1.1.动态内存分配动态内存分配22结构体与指针结构体与指针什么是动态内存分配,和普通变量定义有什么区别?2.2.结构体与指针结构体与指针3.3.结构体与链表结构体与链表普通变量定义有什么区别?如何使用指针访问结构体成员?链表是一种什么样的数据结构,它和数组有什么区别?链表有哪些基本操作?链表有哪些基本操作?动态内存分配动态内存分配动态内存分配动态内存分配••到目前为止,我们所写的程序的内存分配有以下特点:到目前为止,我们所写的程序的内存分配有以下特点:到目前为止,我们所写的程序的内存分配有以下特点到目前为止,我们所写的程序的内存分配有以下特点1.1.由编译器为我们自动完成;由编译器为我们自动完成;变量的声明(基本数据类型、数组、结构变量的声明(基本数据类型、数组、结构……)意味着内存的分配)意味着内存的分配intx;structstudentstu;floatarrData[100];floatarrData[100];2.2.要分配的内存大小必须在编写程序时就确定,其后不能改变,要分配的内存大小必须在编写程序时就确定,其后不能改变,由于不能到程序运行时再动态分配,因此只能提前分配足够由于不能到程序运行时再动态分配,因此只能提前分配足够大的内存空间,造成浪费。大的内存空间,造成浪费。structstudent[100];//要录入若干个学生信息[]动态内存分配动态内存分配动态内存分配动态内存分配••动态内存分配机制就是允许程序员在程序运行时根据动态内存分配机制就是允许程序员在程序运行时根据动态内存分配机制就是允许程序员在程序运行时根据动态内存分配机制就是允许程序员在程序运行时根据实际需要动态地申请内存。动态内存分配是高级语言实际需要动态地申请内存。动态内存分配是高级语言提供的重要特性之一。提供的重要特性之一。voidmain(){intxa[10];pStxaintx,a[10];...int*p=newint;STUDENT*pStu=spStu静态内存静态内存STUDENTpStu=newSTUDENT;char*s=newchar[100];...动态内存...delete[]s;deletepStu;deletep;动态内存p}动态内存分配简介动态内存分配简介动态内存分配简介动态内存分配简介••C/C++C/C++语言支持动态内存分配机制,允许程序员在程语言支持动态内存分配机制,允许程序员在程//语言支持动态内存分配机制,允许程序员在程语言支持动态内存分配机制,允许程序员在程序运行时按实际需要动态地申请内存。序运行时按实际需要动态地申请内存。C++C++通过运算通过运算符符new//delete,支持动态内存分配:,支持动态内存分配:new类型(初值)new类型[数组长度]delete指针变量名delete[]指针变量名new类型[数组长度]new和delete运算符delete [] 指针变量名int*pi=newint;float*pf=newfloat(3.14159);h*th[100]char*str=newchar[100];int**pArr2D=newint[4][5];deletepf;//delete用于释放动态分配的单个变量deletepf;//delete用于释放动态分配的单个变量delete[]str;//delete[]用于释放动态分配的一个数组delete[]pArr2D;//delete[]用于释放动态分配的一个数组示例示例1.voidmain()2.{3intnLen=0;示例示例3.intnLen=0;4.int*pData=NULL;5.coutInputthenumberofintergers:;6.cinnLen;7.if(nLen0){8.pData=newint[nLen];//按需分配数组9.}10if(pData==NULL)return;10.if(pData==NULL)return;11.12.//读入每个数组元素13.coutInputallintergers:;14.for(inti=0;inLen;i++)15.cinpData[i];16.17//其它操作17.//其它操作...18.delete[]pData;//释放数组内存19.}动态内存分配的注意事项动态内存分配的注意事项动态内存分配的注意事项动态内存分配的注意事项••动态内存是由系统从动态内存资源(动态内存是由系统从动态内存资源(heapheap)中分配给)中分配给动态内存是由系统从动态内存资源(动态内存是由系统从动态内存资源(pp)中分配给)中分配给程序员的,在编译时不知道要使用多少,要等到运行程序员的,在编译时不知道要使用多少,要等到运行时才知道时才知道•用new运算符申请动态内存可能会失败,此时返回的运算符申请动态内存可能会失败,此时返回的指针为指针为NULLNULL,必须检查返回指针以确定申请是否成功,必须检查返回指针以确定申请是否成功••动态内存的申请和释放都是由程序员进行,由于释放动态内存的申请和释放都是由程序员进行,由于释放内存的地方不可预测,系统不能替程序员自动完成内内存的地方不可预测,系统不能替程序员自动完成内存的回收所以存的回收所以C++C++程序中申请的动态内存必须要记程序中申请的动态内存必须要记存的回收,所以存的回收,所以C++C++程序中申请的动态内存必须要记程序中申请的动态内存必须要记得释放(得释放(deletedelete),否则会产生内存泄漏,造成系统),否则会产生内存泄漏,造成系统的不稳定和资源浪费的不稳定和资源浪费的不稳定和资源浪费的不稳定和资源浪费动态内存分配的注意事项动态内存分配的注意事项动态内存分配的注意事项动态内存分配的注意事项••有一些好的习惯可以帮助我们避免内存泄漏错误:有一些好的习惯可以帮助我们避免内存泄漏错误:有些好的习惯可以帮助我们避免内存泄漏错误有些好的习惯可以帮助我们避免内存泄漏错误1.1.尽可能保证同一块内存的分配和释放在同一个函数中进行尽可能保证同一块内存的分配和释放在同一个函数中进行2.2.注意函数中所有注意函数中所有returnreturn返回点之前的代码,看是否有正确返回点之前的代码,看是否有正确地释放内存地释放内存地释放内存地释放内存3.3.如果确实需要在一个函数中分配内存,在另一个函数中释放,如果确实需要在一个函数中分配内存,在另一个函数中释放,请在函数注释里说明请在函数注释里说明请在函数注释里说明请在函数注释里说明4.4.写程序时,写完内存分配语句后昀好马上写上内存释放语句,写程序时,写完内存分配语句后昀好马上写上内存释放语句,以免遗忘以免遗忘动态和静态内存分配的对比动态和静态内存分配的对比动态和静态内存分配的对比动态和静态内存分配的对比••静态内存分配静态内存分配••动态内存分配动态内存分配静态内存分配静态内存分配––通过变量、参数声明来分通过变量、参数声明来分配(编译器自动完成);配(编译器自动完成);动态内存分配动态内存分配––通过通过newnew运算符来分配运算符来分配(程序员完成);(程序员完成);配(编译器自动完成);配(编译器自动完成);––使用系统为函数使用系统为函数提供的栈提供的栈内存空间(内存空间(stackstack););(程序员完成);(程序员完成);––使用系统提供的堆内存使用系统提供的堆内存空间(空间(heapheap););––程序执行到离开变量作用程序执行到离开变量作用域时释放内存(编译器自域时释放内存(编译器自pp––由程序员使用由程序员使用deletedelete运算符来释放内存运算符来释放内存动完成);动完成);––使用简便,但会造成资源使用简便,但会造成资源浪费浪费––按需分配,不会造成资按需分配,不会造成资源浪费,但容易产生内源浪费,但容易产生内存漏的错误极存漏的错误极浪费。浪费。存泄漏的错误,而且极存泄漏的错误,而且极难发现。难发现。CC和和C++C++的动态内存分配对比的动态内存分配对比CC和和C++C++的动态内存分配对比的动态内存分配对比••CC语言通过语言通过malloc//free函数,支持动态内存分配函数,支持动态内存分配语言通过语言通过//函数,支持动态内存分配函数,支持动态内存分配void*malloc(intnSize);voidfree(void*pMemory);–malloc函数本身并不识别要申请的内存是什么类型,只关心内存的总字节数,且返回值类型是void*,所以在调用时要显式地进行类型转换,将void*转换成所需要的指针类型,也要显地进行类型转换,将void转换成所需要的指针类型,也要显式地计算待分配的内存字节数intint*p=(*p=(intint*)*)mallocmalloc((sizeofsizeof((intint)*length);)*length);继续保持对数的兼容但我们推•C++继续保持对malloc/free函数的兼容,但我们推荐使用C++的new/delete运算符进行动态内存操作:运算符可以自动进行类型转换和检查使用起来方便得多–new运算符可以自动进行类型转换和检查,使用起来方便得多intint*p=*p=newnewintint[length];[length];–在为C++对象分配内存时,new和malloc有重大区别指向结构体的指针指向结构体的指针指向结构体的指针指向结构体的指针••和指向整型、浮点型等基本数据类型的指针一样,指和指向整型、浮点型等基本数据类型的指针一样,指和指向整型、浮点型等基本数据类型的指针样,指和指向整型、浮点型等基本数据类型的指针样,指向结构体变量的指针内容是该结构体变量的首地址:向结构体变量的指针内容是该结构体变量的首地址:typedefstructstudent指针变量pstu{unsignedshortusYear;charbyMonth;usYearbyMonthbyDay低内存地址指针变量pycharbyDay;unsignedintnID;boolbMalenID低内存地址boolbMale;floatfMarks;}STUDENT;bMaleSTUDENTstu;STUDENT*pstu=&stu;fMarks高内存地址变量stu变量stu指向结构体的指针指向结构体的指针指向结构体的指针指向结构体的指针••可以使用结构体的指针结合“可以使用结构体的指针结合“--”运算符访问结构体”运算符访问结构体可以使用结构体的指针结合可以使用结构体的指针结合运算符访问结构体运算符访问结构体变量的各成员:变量的各成员:STUDENTstu;STUDENT*pstu=&stu;pstu-usYear=1990;//相当于stu.usYear=1990;tbMth1//相当于tbMth1pstu-byMonth=1;//相当于stu.byMonth=1;••也可以通过取内容运算符“也可以通过取内容运算符“**”结合“”结合“..”运算符访问”运算符访问也可以通过取内容运算符也可以通过取内容运算符结合结合..运算符访问运算符访问结