第7章109间接访问-指针.

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

第7章间接访问—指针指针的概念指针运算与数组动态内存分配字符串再讨论指针作为函数参数和返回值指针数组与多级指针指向多维数组的指针指向函数的指针指针介绍本章将介绍C++语言的一个重要的特性:指针,为了成为一个优秀的C++语言程序员,你必须掌握指针并熟练地使用它们。指针•是内存的地址并可作为数据•是一个灵活和危险的机制•允许共享处理数据•允许内存动态分配(只要需要,而非预先定义)指针的概念指针就是把地址作为数据处理指针变量:存储地址的变量变量的指针:当一个变量存储另一个变量的地址时,那我们说它就是那个变量的指针使用指针的目的:提供间接访问指针的概念续如在某一程序中定义了intx=2;如系统给x分配的空间是1000号单元,则指向x的指针是另一个变量p,p中存放的数据为10001000号单元的内容有两种访问方式:访问变量x(直接访问)访问变量p指向的单元的内容(间接访问)100021000xp定义指针变量定义指针变量要告诉编译器该变量中存放的是一个地址。指针变量的主要用途是提供间接访问,因此也需要知道指针指向的单元的数据类型指针变量的定义类型标识符*指针变量;如:int*intp;double*doublep;int*p,x,*q;指针变量的操作如何让指针指向某一变量?因为我们不知道系统分配给变量的真正地址是什么。用地址运算符“&”解决。如表达式“&x”返回的是变量x的地址。如:intp=&x;&运算符后面不能跟常量或表达式。如&2是没有意义的,&(m*n+p)。也是没有意义的如何通过指针变量处理和改变它所指向的单元的值?用引用运算符“*”解决。如*intp表示的是intp指向的这个单元的内容。如:*intp=5等价于x=5在对intp使用引用运算之前,必须先对intp赋值指针实例如有:intX,*intp,Y;X=3;Y=4;intp=&X;1000intp10044Y10003X如执行:*intp=Y+4;1000intp10044Y10008X注意:不能用intp=100;因为我们永远不知道变量存储的真实地址,而且程序每次运行变量地址可能都不同。指针使用指针变量可以指向不同的变量。如上例中intp指向x,我们可以通过对intp的重新赋值改变指针的指向。如果想让intp指向y,只要执行intp=&y就可以了。这时,intp与x无任何关系。同类的指针变量之间可相互赋值,表示二个指针指向同一内存空间。空指针指针没有指向任何空间空指针用常量NULL表示,NULL的值一般赋为0不能引用空指针指向的值指针变量的使用设有定义intx,y;int*p1,*p2;1000x1004y1008p11012p2执行语句:x=23;y=234;100023x1004234y1008p11012p2执行语句:p1=&x;p2=&y;100023x1004234y10081000p110121004p2执行语句:*p1=34;p2=p1;100034x1004234y10081000p110121000p2指针实例有以下结构Ap1aBp2b比较执行p1=p2和*p1=*p2后的不同结果。解:Ap1aBp2bBp1aBp2b指针的初始化指针在使用前必须初始化。和别的变量一样,定义指针不初始化是一个比较普通的错误。没有初始化的指针可能指向任意地址,对这些指针作操作可能会导致程序错误。NULL是一个特殊指针值,称为空指针。它的值为0。它可被用来初始化一个指针,表示不指向任何地址。思考:int*p;*p=5;有什么问题?第7章间接访问—指针指针的概念指针运算与数组动态内存分配字符串再讨论指针作为函数参数和返回值指针数组与多级指针指向多维数组的指针指向函数的指针指针运算和数组指向数组元素的指针数组元素是一个独立的变量,因此可以有指针指向它。如:p=&a[1],p=&a[i]数组元素的地址是通过数组首地址计算的。如数组的首地址是1000,则第i个元素的地址是1000+i*每个数组元素所占的空间长度指针与数组在C++中,指针和数组关系密切,几乎可以互换使用数组名可以看成是常量指针,对一维数组来说,数组名是数组的起始地址,也就是第0个元素的地址如执行了p=array,则p与array是等价的,对该指针可以进行任何有关数组下标的操作例如:有定义inta[10],*p并且执行了p=a,那么可用下列语句访问数组a的元素for(i=0;i10;++i)coutp[i];指针运算指针+1表示数组中指针指向元素的下一元素地址;指针-1表示数组中指针指向元素的上一元素地址;合法的指针操作:p+k,p-k,p1-p2指针保存的是一个地址,地址是一个整型数,因此可以进行各种算术运算,但仅有加减运算是有意义的。指针运算与数组有密切的关系数组元素的指针表示当把数组名,如intarray,赋给了一个同类指针intp后,intarray的元素可以通过intp访问。第i个元素的地址可表示为intp+i,第i个元素的值可表示为*(intp+i)。通过指针访问数组时,下标有效范围由程序员自己检查。如输出数组a的十个元素方法3:for(p=a;pa+10;++p)cout*p;方法2:for(i=0;i10;++i)cout*(a+i);方法1:for(i=0;i10;++i)couta[i];方法4:for(p=a,i=0;i10;++i)cout*(p+i);方法5:for(p=a,i=0;i10;++i)coutp[i];下列程序段有无问题?for(i=0;i10;++i){cout*a;++a;}指针和数组的区别虽然通过指针可以访问数组,但两者本质是不同的。在定义数组时为数组的各个元素分配了全部的存储区,而在定义指针时,仅仅分配四个字节的存储区存放指针地址。只有把一个数组名付给了对应的指针后,指针才能当作数组使用如有:intarray[5],*intp;arrayintp当执行了intp=array后第7章间接访问—指针指针的概念指针运算与数组动态内存分配字符串再讨论指针作为函数参数和返回值指针数组与多级指针指向多维数组的指针指向函数的指针动态分配在C++语言中,每个程序需要用到几个变量,在写程序前就应该知道。每个数组有几个元素也必须在写程序时就决定。有时我们并不知道我们需要多大的数组元素直到程序开始运行。因此希望能在程序中根据某一个当前运行值来决定数组的大小。如设计一个打印魔阵的程序,我们希望先输入魔阵的阶数,然后根据阶数定义一个矩阵动态分配方法这些问题的解决方案就是内存的动态分配。我们定义一个指针,并让它指向一个合适的内存。如:int*scores;scores=内存的起始地址;动态内存分配与回收C++中由new和delete两个运算符替代-运算符new用于进行内存分配:申请动态变量:p=newtype;申请动态数组:p=newtype[size];申请动态变量并初始化:p=newtype(初值);-运算符delete释放new分配的内存:释放动态变量:deletep;释放动态数组:delete[]p;动态内存分配与回收//为简单变量动态分配内存,并作初始化intmain(){int*p;p=newint(99);//动态分配内存,并将99作为初始化值赋给它cout*p;deletep;return0;}动态内存分配与回收//动态字符串的使用intmain(){int*p;char*q;p=newint(5);q=newchar[10];strcpy(q,abcde);cout*pendl;coutqendl;deletep;deleteq;return0;}输出结果:5abcde动态分配的检查new操作的结果是申请到的空间的地址当系统空间用完时,new操作可能失败new操作失败时,返回空指针动态内存分配与回收//动态分配检查intmain(){int*p;p=newint;if(!p){coutallocationfailure\n;return1;}*p=20;cout*p;deletep;return0;}assert宏assert()宏在标准头文件cassert中assert()有一个参数,表示断言为真的表达式,预处理器产生测试该断言的代码。如果断言不是真,则在发出一个错误消息后程序会终止。#includeiostream#includecassert//包含assert宏的头文件usingnamespacestd;intmain(){int*p;p=newint;assert(p!=0);//p等于0,则退出程序*p=20;cout*p;deletep;return0;}内存分配的进一步介绍静态分配:对全局变量和静态变量,编译器为它们分配空间,这些空间在整个程序运行期间都存在自动分配:函数内的局部变量空间是分配在系统的栈工作区。当函数被调用时,空间被分配;当函数执行结束后,空间被释放动态分配:在程序执行过程中需要新的存储空间时,可用动态分配的方法向系统申请新的空间,当不再使用时用显式的方法还给系统。这部分空间是从被称为堆的内存区域分配。OSProgramHeap动态分配Stack自动分配Globevariables静态分配内存泄漏动态变量是通过指针间接访问的。如果该指针被修改,这个区域就被丢失了。堆管理器认为你在继续使用它们,但你不知道它们在哪里,这称为内存泄露。为了避免出现孤立的区域,应该明白地告诉堆管理器这些区域不再使用。可以采用delete操作,它释放由new申请的内存。当释放了内存区域,堆管理器重新收回这些区域,而指针仍然指向堆区域,但不能再使用指针指向的这些区域。要确保在程序中同一个区域释放一次。释放内存对一些程序不重要,但对有些程序很重要。如果你的程序要运行很长时间,而且存在内存泄漏,这样程序会耗尽所有内存,直至崩溃。动态空间分配示例输入一批数据,计算它们的和。数据个数在设计程序时尚无法确定。存储一批数据应该用数组,但C++语言的数组大小必须是固定的。该问题有两个解决方案:开设一个足够大的数组,每次运行时只使用一部分。缺点:浪费空间用动态内存分配根据输入的数据量申请一个动态数组#includeiostreamusingnamespacestd;intmain(){int*p,i,n,sum=0;coutAnarraywillbecreateddynamically.\n\n;coutInputanarraysizenfollowedbynintegers:;cinn;if(!(p=newint[n]))exit(1);for(i=0;in;++i)cinp[i];for(i=0;in;++i)sum+=p[i];delete[]p;coutNumberofelements:nendl;coutSumoftheelements:sumendl;return0;}可改为:p=newint[n];assert(p!=NULL);第7章间接访问—指针指针的概念指针运算与数组动态内存分配字符串再讨论指针作为函数参数和返回值指针数组与多级指针指向多维数组的指针指向函数的指针字符串再讨论字符串的另一种表示是定义一个指向字符的指针。然后直接将一个字符串常量或字符串变量赋给它如char*String,ss[]=“abcdef”;String=“abcde”;String=ss;String“abcde”ProgramOS数据段或代码区栈堆String=“abcde”;的执行结果•字符串常量存储在一个称为数据段的内存区域里•将存储字符串”abcde”的内存的首地址赋给指针变量String。String“abcdef\0”ProgramOS数据段栈堆St

1 / 109
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功