您好,欢迎访问三七文档
第7章指针与引用-2-本章内容安排7.1创建和使用指针变量7.2栈和堆(new与delete动态内存分配)7.3堆中创建、访问与删除对象7.4创建和使用引用7.5数据成员中的指针与引用7.6复制构造函数中的深拷贝与浅拷贝7.7指针和引用的陷阱-3-1、地址的概念地址:内存单元的编号就是该单元的地址,它表明了内存单元在内存中的相对位置变量保存在内存中,不同类型变量占用内存单元的数量不同变量的地址:变量占用的首个内存单元的地址2000…02…2002inta;如,变量a占用的是内存的2000~2003四个单元,变量a的地址为2000。源代码中写a=5;我们可以理解为将5赋值给变量a;而计算机在执行程序时,只是将5送入2000~2003四个内存单元中-4-【例7_1】查看变量的地址#includeiostreamintmain(){shortsVar=5;longlVar=65535;floatfVar=3.14f;std::coutShort:\tsVar\tAdd:\t&sVar\n;std::coutLong:\tlVar\tAddr:\t&lVar\n;std::coutFloat:\tfVar\tAddr:\t&fVar\n“;return0;}取变量地址运算符:&sVar。\t为转义字符,输出一个制表符。\\用于输出\,\输出双引号,\’输出单引号每个变量都有确定的地址编译器确定应分配内存的数量,及对应的地址程序员不用关心地址的细节,只需知道如何访问变量即可-5-2、定义指针变量C++中可以定义特殊的变量(指针变量),用于保存普通变量的地址int*pAge=NULL;定义变量时,变量名pAge前面的*,表示pAge是一个变量,用来存储一个整型变量的地址,编译器会为指针变量分配内存单元。指针变量的类型:可保存其地址的变量数据类型。NULL为预定义常量,表示空指针,NULL通常等价于0。良好编程习惯:定义指针变量时应对其执行初始化,未初始化的指针称为野指针,非常危险。为指针变量赋值通过&、=运算符,可以将某个变量的地址保存到指针变量中,称指针变量指向某个变量。inthowOld=50;int*pAge;pAge=&howOld;int*pAge2=&howOld;pAge=howOld;double*p=&howOld;-6-指针变量中存储的地址值实际上是一个整数值,但不能将整数值直接赋值给指针变量。赋值时,取地址的变量类型必须与指针变量类型一致。否则编译器报错。X-7-指针变量inta=5;int*pa;pa=&a;指针变量pa指向变量a3、间接运算符*对指针变量执行间接运算*,又称为解除引用,将获得指针所指向地址处的值。unsignedshorthowOld=50;unsignedshortyourAge;yourAge=howOld;unsignedshorthowOld=50;unsignedshort*pAge=&howOld;unsignedshortyourAge;yourAge=*pAge;-8--9-【例7-2】使用指针操作数据#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;}注意*的不同用处定义指针变量inta=50;int*pAge;pAge=&a;int*p=&a;定义指针变量后,指针变量前的*表示解除引用,表示“存储在……处的值”*pAge=50;//将50保存到pAge所指处*(&a)a*可作为乘法运算符*pAge=yourAge*2;-10--11-4、指针的用处实际编程时,很少直接定义指针变量指向某个变量,然后通过指针间接访问该变量。指针的实际应用传递函数参数,实现对实参的间接修改。访问类中成员数据和成员函数;管理堆中的数据(动态内存管理);【例7-3】用指针交换两个整数“函数”章中有swap函数,不成功的交换原因:参数是变量的值=》单向的传递办法:参数是变量的地址=》访问的是同一内存空间-12-voidswap(int*x,int*y){inttemp;temp=*x;*x=*y;*y=temp;std::cout*x,*ystd::endl;}#includeiostreamvoidswap(int*a,int*b);intmain(){inta=3,b=2;swap(&a,&b);std::couta,bstd::endl;return0;}使用指针访问数组定义数组后,数组的所有元素在内存中连续存储数组地址:数组中首个元素的地址。inta[]={2,3,6,1};int*pa=a;-13-aa[0]2320002004a[1]6120082012a[2]a[3]或pa=&a[0];指针变量pa指向数组a传递数组的本质上只是传递数组起始地址,在average函数中,通过指针变量间接访问数组元素。pa++;指针变量pa指向数组a+1-14-【例7-4】使用指针访问数组#includeiostreamdoubleaverage(intarray[],intsize);constintN=10;intmain(){inta[N];int*p=a;//或者p=&a[0];for(intk=0;kN;k++)*(p+k)=k;doubleave;ave=average(a,N);std::coutaverage=ave\n;return0;}或者p[k]=k;或者(int*array,intsize);或者(int*,int);传递的是实参数组的起始地址-15-【例7-4】数组作为函数参数intaverage(intarray[],intsize){intsum=0;for(inti=0;isize;++i){sum+=array[i];}returnsum/size;}数组本身并不包含数据元素个数的信息,传递数组或指针时,往往传递辅助参数表示元素个数。本质上是:int*array传递的是实参数组的起始地址或者sum+=*(array+i);int*p;for(p=array;parray+size;p++){sum+=*p;}-16-本章内容安排7.1创建和使用指针变量7.2栈和堆(new与delete动态内存分配)7.3堆中创建、访问与删除对象7.4创建和使用引用7.5数据成员中的指针与引用7.6复制构造函数中的深拷贝与浅拷贝7.7指针和引用的陷阱-17-1、程序的内存区域每个程序运行时,会创建5个内存区域全局名称空间:全局变量栈:局部变量和函数形参堆:自由存储区寄存器:用于内部管理,CPU内部的临时数据、指令缓存,状态管理代码空间:保存程序指令-18-栈机制栈用于保存函数中定义的局部变量和函数形参。调用函数时,系统在栈中创建所有局部变量及形参,函数返回后,系统将清除栈中对应的数据。栈中的数据往往都有变量与其对应,通过变量名访问。栈中数据的创建和清除由系统自动完成。局部变量随着函数的返回被丢弃,无法再访问。全局变量存在于整个程序的运行期间,整个程序中都能访问,但全局变量容易出错、难以理解与维护,避免使用。-19-堆机制堆是预留给程序员的大块内存,程序员可以从堆中请求内存空间,使用完成后释放内存空间。请求的内存空间通过指针标识,通过指针间接访问,堆中的内存空间没有变量与其对应;函数返回后系统会自动清理栈,而不会清理堆,堆空间在显示释放前,一直可以访问;堆中请求的空间由程序员负责释放,不再需要的信息保留在堆中称为内存泄漏。-20-2、动态请求堆空间使用new运算符,可以从堆中分配内存。情况一:分配单个数据int*pPointer;pPointer=newint;*pPointer=75;从堆中分配可存储1个int数据的空间。堆中分配的内存,没有对应的变量,只能通过指针间接访问从堆中分配内存可能会失败,使用指针前一定要判断是否分配成功。老式编译器失败后返回NULL指针,新的编译器会抛出异常(后面讨论)。-21-动态请求堆空间情况二:分配多个数据int*pPointer;pPointer=newint[10];*pPointer=75;*(pPointer+1)=85;分配堆空间时,可以指定分配数据的数量,从而请求可保存多个数据的存储空间。*pPointer访问所指向的第一个数据,*(pPointer+n)访问之后的第n个数据,注意不能超过所分配的内存界限。-22-3、释放堆空间使用delete运算符,可以释放请求的堆空间使用完堆内存区域后,必须调用delete释放相应空间,将内存归还给堆,避免内存泄漏。情况一:释放单个数据int*pData=newint;deletepData;//将请求的空间归还给堆情况二:释放多个数据空间int*pData=newint[10];delete[]pData;//将请求的空间归还给堆动态请求的多个数据,如果只使用delete释放,将造成内存泄漏。-23-【例7-5】new和delete示例#includeiostreamintmain(){int*pHeap=newint;if(pHeap==NULL){std::coutError!NomemoryforpHeap!\n;return1;}*pHeap=7;std::cout*pHeap:*pHeap\n;deletepHeap;return0;}-24-4、悬摆指针问题堆中动态请求的存储空间,对指针执行1次delete,将释放对应的空间,如果对该空间再次调用delete,将导致程序崩溃。int*pNumber=newint;deletepNumber;deletepNumber;//*pNumber;delete指针后,该指针将成为悬摆指针(或野指针、迷失指针),解析或再次delete该指针,会导致程序崩溃。释放指针所指向堆内存后,应将指针赋值为NULL或指向重新分配的内存空间。deletepNumber;pNumber=NULL;良好编程习惯:对指针执行运算前,判断该指针是否为NULL-25-delete的本质voidfun(){int*pa=newint(5);*pa=10;……deletepa;std::coutpastd::endl;}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-本章内容安排7.1创建和使用指针变量7.2栈和堆(new与delete动态内存分配)7.3堆中创建
本文标题:第7章指针与引用.
链接地址:https://www.777doc.com/doc-2111871 .html