您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 公司方案 > 02指针与动态内存管理.
第02章指针与动态内存分配-2-本章内容安排指针与动态内存分配函数及参数传递雇员管理系统版本1(数组)雇员管理系统版本2(动态内存分配)-3-1、指针变量地址的概念定义一个变量,程序执行后数据会加载到内存中的某个地方,计算机如何找到这个地方?地址:内存按字节编号,0、1、2……存储单元的编号就是该单元的地址,它表明了该存储单元在内存中的位置系统根据变量的地址而不是任何别的东西寻找某个变量。变量的地址:变量占用的首个存储单元的地址-4-变量的地址变量的地址变量a占用的是内存的2000~2003四个单元,变量a的地址为2000。源代码中写a=5;我们可以理解为将5赋给变量a;而计算机在执行程序时,只是将5送入2000~2003四个存储单元中。2000…02…2002inta;-5-指针变量inta=5;int*pa;pa=&a;指针变量pa指向变量a-6-2、指针变量的使用要点引用前一定要初始化inta=5;int*pa;//pa=&a;一定要初始化*pa=10;-7-指针变量的使用要点数据类型要匹配指针变量的数据类型,必须与其所指向的变量的数据类型一致。不可以在不同类型指针变量之间赋值。指针变量中存储的是一个表示地址的整数值,但不可以将一个整数值直接赋给指针变量。-8-指针变量的使用要点void指针及强制类型转换inta=7,*pa=&a;doubleb=2.5,*pb=&b;void*pv;pv=pa;cout*(int*)pvendl;pv=pb;cout*(double*)pvendl;任意类型指针都可赋值给void类型符合原来的类型-9-3、指针与一维数组通过下标访问数组元素inta[10];intk;for(k=0;k10;k++){a[k]=k;}程序员负责检查下标是否越界!-10-指针与一维数组通过数组名访问数组元素inta[10];intk;for(k=0;k10;k++){*(a+k)=k;}-11-指针与一维数组通过指针变量访问数组元素inta[10];intk,*p;p=a;for(k=0;k10;k++){*(p+k)=k;}或p=&a[0];或者p[k]=k;-12-指针与一维数组指针变量和数组名的使用区别a[k]p[k]*(a+k)*(p+k)for(k=0;k10;k++){*p++=k;}a不能被改变X*a++=k;-13-4、指向数组的指针数据类型(*指针变量名)[常量表达式]inta[2][3]={……};int(*p)[3];p=a;for(inti=0;i2;i++){for(intj=0;j3;j++){p[i][j]=……}}指向数组的指针常用于指向二维数组-14-指向数组的指针访问数组元素的其它方式a[i][j]p[i][j]*(a[i]+j)*(p[i]+j)*(*(a+i)+j)*(*(p+i)+j)-15-5、指针数组数据类型*变量名[常量表达式]inta,b,c,d;int*p[4]={&a,&b,&c,&d};intaa[2][3];int(*pa)[3];pa=aa;定义含4个元素的指针数组,p只是数组名pa是指针变量,指向含3个int元素的一维数组-16-6、二级指针指向指针的指针inta=a;int*pa=&a;int**ppa=&pa;a=5;*pa=5;**ppa=5;-17-二级指针示例二级指针经常与指针数组配合使用char**p;char*name[]={“hello”,“good”,“world”,“bye”,“”};p=name;while(**p!=NULL){cout*p++endl;}运行结果hellogoodworldbye判断第一个字符是否为’\0’-18-7、动态内存分配开辟某种类型的单个空间int*p;if((p=newint)==NULL){cout“error”endl;exit(0);}*p=5;……deletep;用相同类型的指针接收malloc返回void*-19-动态内存分配开辟带初值的某种类型的单个空间int*p;p=newint(5);cout*pendl;……deletep;分配空间并初始化为5-20-动态内存分配开辟多个元素的空间int*p;p=newint[10];*p=5;*(p+1)=6;//或p[1]=6……delete[]p;分配10个int元素空间不能初始化删除多个元素,[]必不可少绝对不能使用*p++=6;-21-动态内存分配注意事项避免内存泄漏int*pa,*pb;pa=newint(5);pb=newint(10);pa=pb;……初值为5的空间无法再访问-22-动态内存分配注意事项普通变量不能通过delete释放inta=5;int*pa=&a;……deletepa;通过编译,但出现运行错误-23-动态内存分配注意事项不能对动态请求的内存连续使用delete释放2次;注意delete的本质voidfun(){int*pa=newint(5);*pa=5;……deletepa;coutpaendl;}2000pa栈52000堆X-24-动态内存分配注意事项另外一种形式的内存泄漏voidfun(){int*pa=newint(5);……}intmain(){fun();……return0;}X2000pa栈52000堆fun返回后,pa被释放,5所占用的内存不可访问!!X-25-8、常指针和指向常量的指针指向常量指针constchar*pc=“abcd”;或charconst*pc=“abcd”;pc所指向的字符串不能被修改。pc[3]=‘a’;但pc可以指向别的字符串chars[]=“hello”;pc=s;X-26-常指针和指向常量指针常指针char*constpc=“abcd”;pc不能指向别的字符串,但可改变指针所指向的内容。pc[2]=‘a’;chars[]=“hello”;pc=s;X-27-常指针和指向常量指针指向常量的常指针constchar*constpc=“abcd”;pc不能指向别的字符串,也不能改变指针所指向的内容。pc[2]=‘a’;chars[]=“hello”;pc=s;XX-28-本章内容安排指针与动态内存分配函数及参数传递雇员管理系统版本1(数组)雇员管理系统版本2(动态内存分配)-29-54mainxy函数的值传递函数的参数是局部变量,栈中intsum(inta,intb){returna+b;}intmain(){intx(5),y(4);coutsum(x,y)endl;return0;}sum54ab运行结果9-30-54main2000xysum20004ab函数的指针传递voidsum(int*a,intb){*a+=b;}intmain(){intx(5),y(4);sum(&x,y);coutxendl;return0;}指针a指向x运行结果9-31-函数的指针传递voidxhg(int*a,int*b){inttmp;tmp=*b;*b=*a;*a=tmp;}intmain(){intx(5),y(4);xhg(&x,&y);coutx‘‘yendl;return0;}-32-函数的指针传递voidxhg(int*a,int*b){int*tmp;tmp=b;b=a;a=tmp;}intmain(){intx(5),y(4);xhg(&x,&y);coutx‘‘yendl;return0;}运行结果54-33-引用的概念引用是变量或对象的别名,建立引用时必须确定引用的对象,对引用的操作实际上就是对被引用者的操作。inti=1;int&ri=i;//以后对ri的操作,实际上操作的是i//可以认为ri和i在内存中占用相同的单元-34-函数的引用传递引用只是别名,并不为其分配存储单元voidsum(int&a,intb){a+=b;}intmain(){intx(5),y(4);sum(x,y);coutxendl;return0;}54mainsum4xy(a)ba和x实质是同一个东西-35-函数返回指针返回指向内存某处的指针char*elem(char*s,intn){return&s[n];}intmain(){charstr[]=“C++Program”;char*pc=elem(str,5);*pc=‘A’;coutstrendl;return0;}需要定义一个指针变量接收返回值运行结果C++PAogram-36-函数返回引用返回对某个变量的引用char&elem(char*s,intn){returns[n];}intmain(){charstr[]=“C++Program”;elem(str,5)=‘A’;coutstrendl;return0;}无需定义一个变量接收返回值运行结果C++PAogram-37-返回引用和指针的陷阱不能返回指向局部变量的指针char*elem(char*s,intn){charc=s[n];return&c;}intmain(){charstr[]=“C++Program”;char*pc=elem(str,5);*pc=‘A’;coutstrendl;return0;}危险!!!c只是局部变量-38-返回引用和指针的陷阱不能返回对局部变量的引用char&elem(char*s,intn){charc=s[n];returnc;}intmain(){charstr[]=“C++Program”;elem(str,5)=‘A’;coutstrendl;return0;}危险!!!c只是局部变量-39-函数的递归调用求阶乘longfact(intn){if(n==1)return1;returnn*fact(n-1);}intmain(){inta=fact(4);coutaendl;return0;}递归的终止条件-40-函数的递归调用递归的过程fact(4)4nfact(3)3n4*fact(3)fact(2)2nfact(1)1n3*fact(2)2*fact(1)return1126-41-函数参数的默认值intsum(inta,intb=2,intc=3){returna+b+c;}intmain(){coutsum(2)endl;coutsum(2,5)endl;coutsum(2,3,6)endl;return0;}运行结果71011从某个位置开始,右侧全部参数指定默认值-42-内联函数内联函数的基本思想函数调用便于模块化设计,程序结构清晰但函数调用占用一定的系统资源:保护现场、参数入栈……内联函数:将函数的编译后的模块直接嵌入调用处,避免函数调用的开销。适用于代码量少的函数,且不能为递归函数-43-内联函数内联函数的示例inlineintadd(inta,intb){returna+b;}intmain(){intx=add(2,4);coutxendl;return0;}将编译好的add模块替换到此处-44-尽量少用define宏避免使用#define定义宏#defineDIV(x,y)((x)/(y))intmain(){intx=DIV(2,4);coutxendl;return0;}inlinefloatdiv(floatx,floaty){returnx/y;}在编译之前进行源代码替换,无类型检查-45-函数重载重载的概念多个函数使用相同的函数名,但确保函数的参数类型或参数个数不同。不能仅仅凭函数的返回类型进行重载通过重载,可实现对不同类型参数进行调用的统一版本。-46-函数重载重载的应用intsquare(inti){returni*i;}long
本文标题:02指针与动态内存管理.
链接地址:https://www.777doc.com/doc-3049357 .html