已阅读5页,还剩66页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1,第六章指针、引用和动态空间管理,本章目标掌握定义各种指针和通过指针进行数据间接访问的方法。了解指针和数组的关系,掌握利用指针访问数组元素的方法。掌握利用指针传递数据参数的方法。了解引用的概念和定义各种引用的方法,掌握利用引用传递数据的方法。掌握动态空间的申请和释放方法,会利用指针操纵动态空间。了解如何使用指针构造复杂的数据结构,如:链表,2,前言指针是c/c+的一个重要概念,正确而灵活地运用它,可以有效地表示复杂的数据结构;能动态分配内存,能方便地使用字符串;有效而方便地使用数组;在调用函数时能得到多于一个的值;能直接处理内存等。指针的概念比较复杂,使用也比较灵活。,3,6.1指针的概念与指针变量的定义,6.1.1指针的概念为了能清楚指针的概念,必须先弄清数据在内存中是如何存储和如何读取的。内存空间是由许多顺序排列的内存单元组成的,这些存储单元以字节为单位,即每一个单元就是一个字节。例如:一个int型的变量长度是4个字节,在内存中就占4个单元。给内存单元从0开始顺序编号,这些编号就是内存单元的地址;内存单元中存放的数据称为内存单元的内容。,00110000,00000000,00000000,00000101,00000000,00000000,内存地址,内存内容,01234.2000200120022003,00000000,00000000,00000011,5,在程序中一般是通过变量名对内存单元进行存取的。其实,程序经过编译后已经将变量名转换为变量的地址,对变量值的存取实际上都是通过地址进行的。,6,对内存单元的访问有两种常用的方式:直接访问和间接访问,直接访问方式就是编译系统能够自动地根据变量名与地址的对应关系(这个关系是在编译时确定的)完成相应的操作。这种情况下,我们对数据的存取都是通过变量名进行的,并没有去关心变量对应的地址。例如:程序已经定义好了变量inti=3,编译时系统分配20002003四个字节给i,在用到变量i时,系统就会根据变量名与地址的对应关系,找到变量i的地址,并取出数据3。,i,00000000,00000000,00000000,00000011,2000,2003,7,但是,对变量的访问还有一种常用的方式:间接访问。所谓间接访问就是需要先设法“找到”或“算出”某个变量的存储地址,然后再根据这个地址访问该变量。这种情况下,我们就需要关心地址,这时,地址要作为一种特殊的数据被处理。这样,就需要一种特殊的变量,专门用来存放地址。例如:我们定义了一个变量ip,用来存放整型变量的地址。ip也是一个变量,ip分配的内存单元地址是3000到3003,通过下列语句将变量i的地址存放到变量ip中:ip=int*ip=/此时的*是间接访问操作符,表示ip所指向的数据,11,6.1.2指针变量的定义和初始化,指针变量就是专门用来存放地址的变量。指针变量的定义格式:类型修饰符*变量名=指针表达式;例如:1、int*pd1,*pd2;定义了两个整型的指针变量,未赋初值。2、doubled,*pd1=并且这两个指针变量均被初始化为指向变量d。定义了一个字符型指针变量s,并被初始化为指向一个字符串,将字符串的内存首地址赋给指针s。4、void*pd3=NULL,*pd4=0;定义了两个无类型指针变量pd3和pd4,并且赋初值为空。Void指针表示它只是一个指针,可以存放一个内存地址,但是如何解释这个地址中存放的数值还不确定。5、long*pd5=NULL;定义了一个长整型指针变量pd5,并赋初值为空。当一个指针不指向任何内存地址时,可以给它赋NULL值。在定义一个指针而没有给它初始化时,指针的值是不定的。那么在程序运行中怎么知道什么时候指针赋了值,什么时候没有赋值呢?可以借助NULL。,13,2、pd=/输出9999间接访问是相对于用变量名直接访问而言的。,15,注意指针变量定义中的*与间接访问运算符*的区别,例:voidmain()inta,b;int*p1,*p2;/变量定义a=100;b=10;p1=/间接访问输出结果:1001010010,变量定义处的*只是表示所定义的变量是指针变量。(与一般变量区别),间接访问处的*是用来联系指针变量和它所指向的变量。*p1,*p2分别代表指针变量p1,p2所指向的变量。(即a,b),16,对表示p1是指针类型,变量名是p1,而不是*p1。这与以前定义普通变量的形式是不同的。4、指针变量只能存放地址(指针),而且只能将变量已分配的地址赋给指针变量。如:int*p;p=/试图把地址1000赋给p是不对的,1000不是内存地址。,22,P=/不能将字符的值作为地址。在对指针初始化时,一定要保证给指针赋的值时一个合法的内存地址,而且这个地址是允许在程序中访问的地址。,23,指针的数据类型,强调指针的数据类型目的是说明该如何解释指针所指空间的数据。任何类型的指针之间可以强制转换,格式是:(类型修饰符*)指针表达式整型、短整型数据都是高位字节放在高地址,低位字节放在低地址。,24,#includevoidmain()char*str=12345678;int*ip=(int*)str;/强制类型转换,将字符型指针转换为整型指针short*sp=(shortint*)str;/强制类型转换,将字符型指针转换为短整型指针couthex*ipendl;/hex表示用16进制形式输出整数couthex*spendl;cout*strendl;coutstrendl;coutsizeofchar*:sizeof(char*)endl;coutsizeofint*:sizeof(int*)endl;coutsizeoflongint*:sizeof(longint*)endl;coutsizeofdouble*:sizeof(double*)endl;/各种类型指针所占字节数,25,高地址,0 x31,0 x32,0 x38,0 x33,0 x34,0 x35,0 x36,0 x37,低地址,str,ip,sp,26,27,用const来限定指针,根据const出现的位置,有三种不同的含义(1)指向常量的指针,即指针所指向的数据为常值。(2)指针常量,即指针本身为常值。(3)指向常量的指针常量。,28,(1)指向常量的指针const出现在指针定义的最开始。该指针指向常量的指针,即指针所指向的数据为常值。所以,在这种情况下,不能通过指针来间接修改指针所指向的数据。如:inti,j;constint*ip=/错误!因为ip是指向常量的指针使用时应注意的几点:,29,(1)指向常量的指针只限制指针的间接访问操作,而不会限制指针变量本身的操作。可以修改指针变量本身的值。比如:*ip=/错误,必须将p2定义成指向常量的指针,30,(2)指针常量const出现在指针名的前面,该指针为指针常量,即不可以修改该指针的值。只能在定义该指针时给它初始化,以后不能再重新赋值。如:inti,j;int*constip=,31,4,(3)指向常量的指针常量将(1)(2)组合起来就构成指向常量的指针常量。指向常量的指针常量必须在定义时赋初值,以后不能改变,并且不能通过指向常量的指针常量间接改变它所指向的数据。如:inti92;intj;constint*constp=/错误!不能通过p间接改变ci的值,32,6.3指针与数组,6.3.1一维数组元素的指针访问方式:一维数组的数组名实际上就是指向该数组第一个单元(下标为0的那个元素)的指针。指向一维数组第一个单元的任何指针都可以象一维数组名那样使用。如:#includevoidmain()inta5=0,1,2,3,4;int*ap=a;for(inti=0;i5;i+)coutaiapiendl;,程序结果:0011223344,33,注意,数组名虽然是指针,但它是指针常量而不是指针变量,因此,不能改变它的值,而只能通过它去访问数组的各个元素。所以,作用于变量的操作不能作用于数组名,如:对于已经定义好的数组a,*+a就是个错误的表达式。而针对指针变量ap就可以执行*+ap操作。,34,用指针对数组操作,对数组的访问,传统上采用下标方式,但还可以采用指针方式。如:若有定义intA10;则数组名A的数据类型是int*,并且指向第一个元素A0,因此,*A和A0访问的是同一个元素,两种表达形式完全等价。同样,*(A+1)可以访问A1,*(A+2)可以访问A2等,即*(A+i)可以访问Ai,*(A+i)与Ai完全等价。实际上,数组的下标操作就是指针操作,Ai只是*(A+i)的另一种表示形式而已。,35,例:intA10,*pa=A;则*(pa+i)和pai访问的是同一个元素Ai。下面的一段程序就是采用不同方式访问数组s的各元素:ints=0,1,2,3,4,5,*p=s;coutendl*pp1*(p+2)s3p4*(s+5);coutendl*+p;coutendl*p;输出结果:01234511,s,p,0,1,3,2,4,5,36,指针移动运算,一、当指针指向的是一个数组时,指针可以在数组的各个元素之间移动。指针的加和减是以指针所指的数据类型的大小为单位进行的(一个数据元素所包含的字节数由指针指向的数据的类型决定,如指针指向整数,则一个数据元素包含4个字节,指针指向字符,则一个数据元素包含1个字节等)1、向后(向高地址方向)指针表达式+n指针变量+=n指针变量=指针变量+n2、向前(向低地址方向)指针表达式-n指针变量-=n指针变量=指针变量-n,37,例如:intm12,*p1=,01234567891011,指针移动时,地址的实际变化值(以字节计量)除了与移动的数据单元数有关,还与指针的类型有关。地址的实际变化值=移动的数据单元数n*sizeof(TYPE)个字节。,38,#includevoidmain()inta5;int*pa=a;for(inti=0;i5;i+)coutpa+i=pa+iendl;,39,二、移动一个单位+前增一,后增一-前减一,后减一前增一:+指针变量后增一:指针变量+前减一:-指针变量后减一:指针变量-前增一和前减一,都是先改变指针变量的值,然后再以改变后的指针值作为表达式的值。后增一和后减一,都是先以指针变量的值,然后再改变指针变量的值。,40,例:intk,*pk=/显示两个不同的地址值,41,三、计算两地址间数据元素的个数,用操作符“-”同类型的两个指针相减,其结果是一个整数,表示两地址之间可容纳的相应类型数据的个数。(不是地址实际间隔的字节数)例如:intn,m12,*p1=/n=5,01234567891011,p1,p2,42,两地址间实际间隔的字节数=两地址间数据单元的个数*sizeof(对应数据类型)。如:m10与m5实际间隔的字节数是5*sizeof(m0)=20个如果指针指向的是一个结构数组,那么,指针的运算就会以一个结构元素所占内存大小为单位。,43,6.3.2多维数组元素的指针访问方式,一维数组与指针关系的结论可以推广到二维数组、三维数组等多维数组。可以把二维数组看成是这样的一维数组:它的每个单元又是一个一维数组。例:intB68;可以把这个二维数组看成是具有六个单元的一维数组,其中每个单元又是一个具有8个单元的int一维数组。B0,B1B5就是6个顺序存储且规格相同的一维数组。B0,B1B5依次是它们的数组名。,44,那么,Bij也就是第i行第j列的元素就可以理解为Bi这个一维数组的第j个元素。Bi本身就具有一维数组下标访问方式,可转换为*(B+i),于是有:Bij*(Bi+j)*(*(B+i)+j)当i,j之一为0或均为0时:Bi0*(Bi+0)*Bi*(B+i)B0j(*(B+0)j(*B)j*(*B+j)B00*(B0+0)*B0*(B+0)*B指向二维数组首行的任何指针可以像二维数组名那样使用。例如:intB1020,(*pb)20=B;,45,6.3.3关于“指向数组的指针”,凡是具有数组首地址的指针都可以称作指向数组的指针。如无特别说明,指向数组的指针应理解为与该数组的数组名等价的指针。定义指向一维数组以及指向二维数组的指针变量的格式分别是:类型修饰符*变量名=一维数组名;类型修饰符(*变量名)列数=二维数组名;,46,6.3.4指针与字符串,字符串是以字符数组的形式存储的,因为字符指针一般会指向一个字符串,所以也就将字符指针看做一个字符串。如:char*str=“string”;等价于charstr=“string”;coutstrendl;/输出串stringcoutstr+3endl;/输出串ing,s,t,r,i,n,g,str,str+3,47,#includevoidmain()charstr1=“arraystring”;char*str2=“pointerstring”;cout“conststring”endl;coutstr1endl;coutstr2endl;coutstr1+6endl;cout*str2endl;coutstr2+8endl;,输出结果:conststringarraystringpointerstringstringpstring,48,补充:指针操作符的综合运用,在与指针有关的操作符中,+,-,*,=,+=,-=是2元操作符,具有其它符合赋值操作符一样几乎最低的优先级(仅高于,)。上述这些操作符的结合性均为从右到左。,49,假定指针p的定义如下:intd=3,6,9,*p=d;注意区分下列指针表达式的含义:*p+;取p所指向单元的数据作为表达式的值,然后使p指向下一个单元。(*p)+;取p所指向单元的数据作为表达式的值,然后使该单元的数据值增1。*+p;使p指向下一个单元,然后取该单元的数据作为表达式的值。+*p;将p所指向的单元的数据增1并作为表达式的值。,int*p=d;初始状态:,intd=3,6,9;,初始状态下,执行*p+后:(表达式*p+的值:3),p,初始状态下,执行(*p)+后:(表达式(*p)+的值:3),p,初始状态下,执行*+p后:(表达式*+p的值:6),p,初始状态下,执行+*p后:(表达式+*p的值:4),p,51,6.3.5指针数组,若数组的每个元素是一个指针,则称为指针数组,例如:int*ip10;ip是一个一维数组,其中的每个元素是一个指向整型数据的指针。指针数组常见应用就是构造字符串符号表,如定义一个记录七天的英文名字的数组:char*week7=Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday;,52,53,6.4指针与函数,6.4.1指针参数“传值”是直接传送方式,指针是一种间接传递方式。通过指针参数的传递,形参指针和实参指针指向同一数据,因此通过形参指针就可以改动实参所指向的数据。,54,6.4.2指针函数:返回指针值的函数,函数可以返回指针值,这样的函数称为指针函数。在定义指针函数时,函数名前必须有*,格式是:类型修饰符*函数名(形式参数表)函数体P171例子6.4.3函数指针:指向函数的指针指向函数的指针称为函数指针,格式为:类型修饰符(*变量名)(形式参数表)=函数名;例如:intf1(intn)int(*pf1)(int)=f1;,55,*a=val1*b=val2*a*b等价于val1val2,10,20,val1,val2,*a=*b;*b=c;voidmain()intx=3,y=5;coutxyendl;swap(,61,#includevoidswap(int,例2:设计函数swap,其功能是交换两个变量的值,要求变量的地址通过引用参数传递。,3,x,a,y,b,5,62,指针参数传递仍然属于”按值传递“方式,即如果形参指针变量的值发生改变,影响不到实参指针变量。但函数要处理的对象并不是形参变量本身而是形参所指向的数据,又因为形参变量与实参变量的值相同,当然形参变量与实参变量指向的数据是同一个单元,因此,我们可以通过在函数中改变形参指针变量所指向的数据达到改变实参指针变量所指向的数据的目的。引用是通过给实参变量起一个别名,达到通过使用别名间接改变别名所代表的变量的目的。应用指针和引用参数的另一个重要目的是减少参数传递过程中的数据复制量,达到节约空间,提高程
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026年丹东市振兴区中小学编制教师招聘笔试备考题库及答案详解
- 2026年武汉市新洲区中小学编制教师招聘考试模拟试题及答案详解
- 2026年南昌市湾里区中小学编制教师招聘考试模拟试题及答案详解
- 2026年山西省晋中市事业编单位人员招聘笔试备考试题及答案详解
- 2026年张家界市武陵源区中小学编制教师招聘考试备考试题及答案详解
- 2026年黄石市下陆区中小学编制教师招聘笔试备考题库及答案详解
- 2026年大连市沙河口区事业编单位人员招聘笔试备考试题及答案详解
- 2026年丽水市莲都区事业编单位人员招聘笔试备考试题及答案详解
- 2026年十堰市张湾区事业编单位人员招聘笔试备考题库及答案详解
- 2026年江门市新会区中小学编制教师招聘考试模拟试题及答案详解
- 2025年生猪屠宰兽医卫生检疫人员考试题(附答案)
- 中药方剂学临床案例分析
- 加油站消防安全应急预案演练计划
- 半导体物理SEMICONDUCTORPHYSICS课件
- 单元教学设计15 一元二次函数、方程和不等式大单元-高中数学单元教学设计
- 交警队交通安全宣传课件
- 2023年湖北省襄阳市生物中考真题(解析版)
- 临床医学检验临床微生物:临床医学检验临床微生物考试答案二
- 食品行业的食品安全风险评估案例分析
- QCT 388-2023 碗形塞片 (正式版)
- 中西医结合治疗肝硬化腹水课件
评论
0/150
提交评论