您好,欢迎访问三七文档
当前位置:首页 > 电子/通信 > 综合/其它 > c++课件第08章指针及其应用
第08章指针及其应用-2-本章内容安排指针的使用栈和堆的概念指针和数组在堆中创建对象-3-1、地址的概念计算机内存被划分为顺序编号的内存单元,0、1、2……地址:内存单元的编号就是该单元的地址,它表明了内存单元在内存中的相对位置变量保存在内存中,不同类型变量占用内存单元的数量不同。变量的地址:变量占用的首个内存单元的地址。-4-变量的地址变量a占用的是内存的2000~2003四个单元,变量a的地址为2000。源代码中写a=5;我们可以理解为将5赋值给变量a;而计算机在执行程序时,只是将5送入2000~2003四个内存单元中。2000…02…2002inta;-5-查看变量的地址#includeiostream#includetriangle.h“intmain(){shortsVar=5;longlVar=65535;floatfVar=3.14f;std::coutShort:\tsVar\tAdd:\t&sVar\n;std::coutLong:\tlVar\tAddr:\t&lVar\n;std::cout“Float:\tfVar\tAddr:\t&fVar\n;’return0;}取变量地址运算符:&sVar。3.14字面常量为double类型,加上后缀f,表示float型。\t为转义字符,输出一个制表符。\\用于输出\,\输出双引号,\’输出单引号。-6-变量的地址编写程序时,没有必要知道每个变量对应的地址,系统为每个变量分配相应的内存单元,每个变量都有确定的地址。编译器根据变量类型确定应分配内存单元数量。并记录对应的地址,系统最终根据地址访问数据,程序员不用关心地址的细节,只需知道如何访问变量即可。-7-2、定义指针变量C++中可以定义特殊的变量(指针变量),用于保存普通变量的地址。int*pAge=NULL;pAge本身也是变量,专门用来存储另一个整型变量的地址编译器会为指针变量分配内存单元。指针变量的类型:可保存其地址的变量数据类型。NULL为预定义常量,表示空指针,NULL通常等价于0。良好编程习惯:定义指针变量时应对其执行初始化,未初始化的指针称为野指针,非常危险。为指针变量赋值通过&、=运算符,可以将某个变量的地址保存到指针变量中,称指针变量指向某个变量。unsignedshorthowOld=50;unsignedshort*pAge;pAge=&howOld;pAge=howOld;-8-指针变量中存储的地址值实际上是一个整数值,但不能将整数值直接赋值给指针变量。赋值时,取地址的变量类型必须与指针变量类型一致。否则编译器报错。X-9-指针变量inta=5;int*pa;pa=&a;指针变量pa指向变量a3、间接运算符*对指针变量执行间接运算*,又称为解除引用,将获得指针所指向地址处的值。unsignedshorthowOld=50;unsignedshortyourAge;yourAge=howOld;unsignedshorthowOld=50;unsignedshort*pAge=&howOld;unsignedshortyourAge;yourAge=*pAge;-10-*的不同用处定义指针变量int*pAge;定义指针变量后,指针变量前的*表示解除引用,表示“存储在……处的值”*pAge=50;//将50保存到pAge所指处*可作为乘法运算符*pAge=yourAge*2;-11--12-4、使用指针操作数据#includeiostreamintmain(){intmyAge;int*pAge=&myAge;myAge=5;std::coutMyAge:\tmyAge\n;std::cout*pAge:\t*pAge\n;*pAge=7;std::coutMyAge:\tmyAge\n;std::cout*pAge:\t*pAge\n;return0;}-13-5、指针的用处实际编程时,很少直接定义指针变量指向某个变量,然后通过指针间接访问该变量。指针的实际应用管理堆中的数据(动态内存管理);访问类中成员数据和成员函数;传递函数参数,实现对实参的间接修改。-14-本章内容安排指针的使用栈和堆的概念指针和数组在堆中创建对象-15-1、程序的内存区域每个程序运行时,会创建5个内存区域全局名称空间:全局变量堆:自由存储区寄存器:用于内部管理,CPU内部的临时数据、指令缓存,状态管理代码空间:保存程序指令栈:局部变量和函数形参-16-栈机制栈用于保存函数中定义的局部变量和函数形参。调用函数时,系统在栈中创建所有局部变量及形参,函数返回后,系统将清除栈中对应的数据。栈中的数据往往都有变量与其对应,通过变量名访问。栈中数据的创建和清除由系统自动完成。局部变量随着函数的返回被丢弃,无法再访问。全局变量存在于整个程序的运行期间,整个程序中都能访问,但全局变量容易出错、难以理解与维护,避免使用。-17-堆机制堆是预留给程序员的大块内存,程序员可以从堆中请求内存空间,使用完成后释放内存空间。请求的内存空间通过指针标识,通过指针间接访问,堆中的内存空间没有变量与其对应;函数返回后系统会自动清理栈,而不会清理堆,堆空间在显示释放前,一直可以访问;堆中请求的空间由程序员负责释放,不再需要的信息保留在堆中称为内存泄漏。-18-2、动态请求堆空间使用new运算符,可以从堆中分配内存。情况一:分配单个数据unsignedshort*pPointer;pPointer=newunsignedshort;*pPointer=75;从堆中分配可存储1个unsignedshort数据的空间。堆中分配的内存,没有对应的变量,只能通过指针间接访问从堆中分配内存可能会失败,使用指针前一定要判断是否分配成功。老式编译器失败后返回NULL指针,新的编译器会抛出异常(后面讨论)。-19-动态请求堆空间情况二:分配多个数据unsignedshort*pPointer;pPointer=newunsignedshort[10];*pPointer=75;*(pPointer+1)=85;分配堆空间时,可以指定分配数据的数量,从而请求可保存多个数据的存储空间。*pPointer访问所指向的第一个数据,*(pPointer+n)访问之后的第n个数据,注意不能超过所分配的内存界限。-20-3、释放堆空间使用delete运算符,可以释放请求的堆空间。使用完堆内存区域后,必须调用delete释放相应空间,将内存归还给堆,避免内存泄漏。情况一:释放单个数据int*pData=newint;…//使用内存deletepData;//将请求的空间归还给堆-21-释放堆空间情况二:释放多个数据空间int*pData=newint[10];…//使用内存delete[]pData;//将请求的空间归还给堆动态请求的多个数据,如果只使用delete释放,将造成内存泄漏。-22-示例程序#includeiostreamintmain(){int*pHeap=newint;if(pHeap==NULL){std::coutError!NomemoryforpHeap!\n;return1;}*pHeap=7;std::cout*pHeap:*pHeap\n;deletepHeap;return0;}-23-4、悬摆指针问题堆中动态请求的存储空间,对指针执行1次delete,将释放对应的空间,如果对该空间再次调用delete,将导致程序崩溃。int*pNumber=newint;…//使用指针deletepNumber;deletepNumber;//*pNumber;delete指针后,该指针将成为悬摆指针(或野指针、迷失指针),解析或再次delete该指针,会导致程序崩溃。-24-悬挂指针问题释放指针所指向堆内存后,应将指针赋值为NULL或指向重新分配的内存空间。int*pNumber=newint;…//使用指针deletepNumber;pNumber=NULL;对NULL指针执行delete运算不会导致程序崩溃,但执行间接运算仍会导致程序崩溃。良好编程习惯:对指针执行间接运算之前,判断该指针是否为NULL。-25-delete的本质voidfun(){int*pa=newint(5);*pa=5;……deletepa;coutpaendl;}2000pa栈52000堆Xdelete只是释放pa所指向的堆空间,对指针pa本身没有任何影响。此时pa仍然指向原先的内存位置,变成了野指针。pa是位于栈中的局部变量,fun返回后pa由系统自动销毁。5、避免内存泄漏典型情况一:没有释放所指内存之前将指针指向新分配的内存int*pNumber=newint;*pNumber=75;pNumber=newint;*pNumber=85;-26-pNumber指向新分配的存储空间后,原先分配的内容为75的内存无法访问,也无法再释放!deletepNumber;-27-避免内存泄漏典型情况二:在函数内分配的内存空间,函数返回之前没有释放voidfun(){int*pa=newint;*pa=5;}intmain(){fun();……}2000pa栈52000堆fun返回后,pa被释放,5所占用的内存不可访问!!Xdeletepa;-28-本章内容安排指针的使用栈和堆的概念指针和数组在堆中创建对象数组的地址定义数组后,数组的所有元素在内存中连续存储数组地址:数组中首个元素的地址。inta[]={2,3,6,1};int*pa=a;-29-aa[0]2320002004a[1]6120082012a[2]a[3]或pa=&a[0];指针变量pa指向数组a-30-使用指针访问数组#includeiostreamintmain(){inta[10];intk;int*p=a;//或者p=&a[0];for(k=0;k10;k++){*(p+k)=k;}return0;}或者p[k]=k;-31-数组作为函数参数intaverage(intarray[],intsize){intsum=0;for(inti=0;isize;++i){sum+=array[i];}returnsum/size;}数组本身并不包含数据元素个数的信息,传递数组或指针时,往往传递辅助参数表示元素个数。本质上是:int*array传递的是实参数组的起始地址-32-数组作为函数参数#includeiostreamintmain(){intscore[]={80,60,90,85};intave=average(score,4);std::coutAveragescore:avestd::endl;return0;}传递数组的本质上只是传递数组起始地址,在average函数中,通过指针变量间接访问数组元素。-33-本章内容安排指针的使用栈和堆的概念指针和数组在堆中创建对象-34-引入SimpleCat类#inlcudeiostreamclassSimpleCat{public:SimpleCat();~SimpleCat();intgetAge()const;voidsetAge(intage){itsAge=age;}private:intitsAge;};-35-引入SimpleCat类SimpleCat::SimpleCat(){std::cout“Constructorcalled\n”;itsAge=1;}SimpleCat::~SimpleCat(){std::cout“Destructorcalled\n”;}intSimpleCat::ge
本文标题:c++课件第08章指针及其应用
链接地址:https://www.777doc.com/doc-2904382 .html