资源预览内容
第1页 / 共54页
第2页 / 共54页
第3页 / 共54页
第4页 / 共54页
第5页 / 共54页
第6页 / 共54页
第7页 / 共54页
第8页 / 共54页
第9页 / 共54页
第10页 / 共54页
亲,该文档总共54页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
指针是指针是C+的精华,也是学习的重点和的精华,也是学习的重点和难点难点正确地使用指针可编写简洁、高效和通正确地使用指针可编写简洁、高效和通用的程序。用的程序。错误的使用指针易使程序运行出错或导错误的使用指针易使程序运行出错或导致系统崩溃致系统崩溃 第第8章章 指针指针8.1 指针和指针变量指针和指针变量8.2 指针和数组指针和数组8.3 指针数组和指向指针的指针指针数组和指向指针的指针8.4 指针和函数指针和函数 8.5 new和和delete运算符运算符8.6 引用和其他类型的指针引用和其他类型的指针8.7 简单链表及其应用简单链表及其应用 第第8章章 指针指针教室必须有编号,也就是教室的教室必须有编号,也就是教室的地址地址。以保证正常的教学管理。以保证正常的教学管理。8.1 指针和指针变量指针和指针变量基本概念基本概念 例例如如,现现在在1-2节节是是我我们们上上课课,在在教教三三402。3-4节节可可能能是是020095班班,教教室室中中上上课课的的班班级级可可以以变变化化,但但在在教教三三402始始终终对对应着这间教室。应着这间教室。 与与教教室室类类似似,计计算算机机中中的的存存储储单单元元也也具具有有这这样样的的性性质质。每每个个单元都必须有它的单元都必须有它的地址地址,以及存放在存储单元的,以及存放在存储单元的内容内容。 由由于于读读、记记代代码码很很麻麻烦烦,因因此此,C+就就将将代代码码翻翻译译成成人人所所熟熟知知的的自自然然语语言言符符号号。这这些些符符号号就就是是代代表表某某个个存存储储单单元元的的变变量量名名或者称为或者称为标识符标识符。 试想,教室的编码如果是这样试想,教室的编码如果是这样0x0065FDE4,你是否会用这个,你是否会用这个编码来管理教室呢?但这个编码就是计算机内存的地址码。编码来管理教室呢?但这个编码就是计算机内存的地址码。402教室教室地址地址教室教室内容内容教三教三02A106 现现在在假假设设,把把地地址址编编码码为为107的的单单元元用用标标识识符符a(如如:称称作作C+专专用用教教室室)代代替替,那那么么,a就就代代表表了了这这个个单单元元的的地地址址。在在C+中,它中,它就是所谓的变量名。就是所谓的变量名。107单元地址单元地址单元内容单元内容 在在算算法法中中,执执行行含含有有变变量量名名为为a的的语语句句或或表表达达式式时时,C+首首先先会会访访问问a所所代代表表的的单单元元地地址址,这这个个过过程程称称为为寻寻址址。显显然然,如如果单元没有地址,果单元没有地址,C+就无法找到这个单元。就无法找到这个单元。 那那么么,单单元元的的地地址址还还有有其其它它寻寻访访办办法法吗吗?为为了了回回答答这这个个问问题,我们再来探讨教室的管理。题,我们再来探讨教室的管理。a8.1 指针和指针变量指针和指针变量基本概念基本概念 一一幢幢楼楼有有若若干干个个教教室室,如如果果临临时时要要找找一一个个教教室室来来上上大大课课,一一种种办办法是逐个寻找哪个教室空闲,这当然很费事。法是逐个寻找哪个教室空闲,这当然很费事。 还还有有一一种种办办法法,是是到到管管理理教教室室的的教教务务室室去去查查找找。教教务务室室的的墙墙壁壁上上有一个大布袋,它上面分布了全校所有教室的有一个大布袋,它上面分布了全校所有教室的代号代号地址代码地址代码。 尽尽管管这这个个布布袋袋子子上上不不可可能能有有教教室室空空间间,但但通通过过访访问问它它上上面面的的教教室室地址地址就可了解就可了解各个教室的各个教室的使用信息。使用信息。例如例如. . . . . . . . .存放教室地址的布袋子存放教室地址的布袋子10601班班107空空 显然,把教室显然,把教室地址地址存放在布袋上的办法为教室管理提供很大方便存放在布袋上的办法为教室管理提供很大方便8.1 指针和指针变量指针和指针变量基本概念基本概念. . . . . . . . . 这这种种管管理理和和访访问问教教室室的的办办法法,也也被被C+的的设设计计者者采采用用,它它们们把类似于把类似于存放教室地址的小口袋称为存放教室地址的小口袋称为指针指针变量变量。存放教室地址的布袋子存放教室地址的布袋子 C+中中,指指针针是是内内存存单单元元的的地地址址。根根据据以以上上类类比比分分析析,指指针针变变量量只只能能存存放放变变量量的的地地址址(指指针针),而而不不能能存存放放一一般般的的数数据据(学生)。(学生)。10601班班107空空指针指针 这这就就象象布布袋袋上上的的小小口口袋袋只只能能存存放放教教室室的的地地址址,而而不不可可能能让让学学生坐在上面上课的性质一样。生坐在上面上课的性质一样。 下面来介绍指针变量的定义和使用下面来介绍指针变量的定义和使用。8.1 指针和指针变量指针和指针变量基本概念基本概念 指针变量的定义方式如下:指针变量的定义方式如下:306a307xint *p1;float *p2;int a;float x;p1306307C+是这样给是这样给p1、p2分配单元分配单元 从从单单元元图图形形可可知知,指指针针变变量量是是专专用用于于存存放放变变量量地地址址的的。图图中中的的箭箭头是为便于形象地描述而加的。头是为便于形象地描述而加的。 如果再定义普通变量如果再定义普通变量a、x:并且在算法中有如上语句:并且在算法中有如上语句:.p1=&a; p2=&x; 那么,执行语句的结果是:那么,执行语句的结果是:p2可以这样来描述它们的关系:指针可以这样来描述它们的关系:指针p1指向指向变量变量a,p2指向指向变量变量x。8.1 指针和指针变量指针和指针变量指针变量的说明指针变量的说明 指针变量的定义方式如下:指针变量的定义方式如下:306a307xint *p1;float *p2;int a;float x;p1306307C+是这样给是这样给p1、p2分配单元分配单元 图图示示可可知知,赋赋值值语语句句是是把把普普通通变变量量的的单单元元地地址址分分别别存存放放到到指指针变量针变量p1、p2中。这相当于把教室的代号中。这相当于把教室的代号放在放在布袋布袋里里。.p1=&a; p2=&x;p2 上上述述赋赋值值语语句句中中,&是是取取地地址址运运算算符符,表表示示取取变变量量a和和x的的地地址址。运运算算过过程程是是:先先由由&取取出出变变量量的的地地址址,然然后后把把地地址址码码赋赋给给指针变量。指针变量。 指指针针变变量量的的命命名名除除与与普普通通变变量量相相同同之之外外,定定义义时时还还必必须须在在左左边加一个边加一个*,以示被定义的是指针变量,但在算法中却没有,以示被定义的是指针变量,但在算法中却没有*。8.1 指针和指针变量指针和指针变量指针变量的说明指针变量的说明 指针变量的定义方式如下:指针变量的定义方式如下:306a307xint *p1;float *p2;int a;float x;p1306307C+是这样给是这样给p1、p2分配单元分配单元.p1=&a; p2=&x;p2 在算法中,指针变量的左边带在算法中,指针变量的左边带*,表示所指单元的内容表示所指单元的内容。例如例如*p1=5; *p2=5.0; 虽然都写成虽然都写成*p1和和*p2,但但定义定义语句语句中的中的*是告诉编译系统:是告诉编译系统:p1、p2是指针变量是指针变量这相当于:这相当于: a=5; x=5.0;55.0*p1*p2 算法语句算法语句中的中的*则表示则表示*p1和和*p2是指针所指单元的内容。是指针所指单元的内容。8.1 指针和指针变量指针和指针变量指针变量的说明指针变量的说明 指针变量的定义方式如下:指针变量的定义方式如下:306a307xint *p1;float *p2;int a;float x;p1306307C+是这样给是这样给p1、p2分配单元分配单元.p1=&a; p2=&x;p2 在算法中,指针变量的左边却允许带在算法中,指针变量的左边却允许带*,例如,例如*p1=5; *p2=5.0;55.0*p1*p2 这这就就是是说说,当当变变量量a被被指指针针p1所所指指时时,该该变变量量所所表表示示的的单元既可称为单元既可称为a,也可称为,也可称为*p1。同理,。同理,变量变量x也是如此。也是如此。 8.1 指针和指针变量指针和指针变量指针变量的说明指针变量的说明 指针变量的定义方式如下:指针变量的定义方式如下:306a307xint *p1;float *p2;int a;float x;p1306307C+是这样给是这样给p1、p2分配单元分配单元p2 如果还有如上定义和语句:如果还有如上定义和语句:那么,算法中语句执行的结果是:那么,算法中语句执行的结果是:*p1*p2,*p3;.p1=&a; p2=&x;p3=&a; 或者或者 p3=p1;p3306*p3 由由于于指指针针p3也也得得到到变变量量a的的地地址址,因因此此变变量量a又又可可称称为为*p3。显显然然,此此时时C+可可通通过过*p1、*p3或或者者a去去访访问问地地址址代代码码为为306的的单元。单元。8.1 指针和指针变量指针和指针变量指针变量的说明指针变量的说明 指针变量的定义方式如下:指针变量的定义方式如下:306a307xint *p1;float *p2;int a;float x;p1306307C+是这样给是这样给p1、p2分配单元分配单元p2 指指针针也也是是一一种种构构造造的的数数据据类类型型,本本例例中中p1、p3的的基基本本类类型型是是int,而,而p2的的基本类型是基本类型是float。如果有以上语句:如果有以上语句:*p1*p2,*p3;.p1=&a; p2=&x;p1=p2; 或者或者 p2=p1; 或者或者 p1=&x;或者或者 p2=&a;C+认为这是错误的语句。认为这是错误的语句。因为它们的因为它们的基本基本类型不同类型不同。8.1 指针和指针变量指针和指针变量指针变量的说明指针变量的说明 指针变量的定义方式如下:指针变量的定义方式如下:306a307xint *p1;float *p2;int a;float x;p1306307C+是这样给是这样给p1、p2分配单元分配单元p2 这也是错误的语句,为什么?这也是错误的语句,为什么?*p1*p2,*p3;.p1=&a; p2=&x;p1=a; 或者或者 p2=x; 因因为为p1是是指指针针变变量量,只只能能存存放放变变量量地地址址。而而p1=a是是要要求求将将变变量量a中中的的数数据据赋赋给给p1,这这就就象象,要要求求将将教教室室中中的的师师生生搬搬到小口袋里那么荒唐。同理,到小口袋里那么荒唐。同理,p2=x也是错误的。也是错误的。8.1 指针和指针变量指针和指针变量指针变量的说明指针变量的说明 指针变量的定义方式如下:指针变量的定义方式如下:306a307xint *p1;float *p2;int a;float x;p1306307C+是这样给是这样给p1、p2分配单元分配单元p2*p1*p2,*p3;.p1=&a; p2=&x; 指指针针变变量量的的值值为为0时时表表示示不不指指向向任任何何单单元元,而而指指针针变变量量的的赋值常数只有一个赋值常数只有一个NULL。例如:例如:p1=NULL; p2=NULL; 或者或者 p1=0; p2=0; 由由于于符符号号NULL的的代代码码为为0,当当将将NULL或或0赋赋给给指指针针变变量量时,该指针就变成空指针,即,时,该指针就变成空指针,即,8.1 指针和指针变量指针和指针变量指针变量的说明指针变量的说明 指针变量的定义方式如下:指针变量的定义方式如下:306a307xint *p1;float *p2;int a;float x;C+是这样给是这样给p1、p2分配单元分配单元,*p3;.p1=&a; p2=&x;p1=NULL; p2=NULL; 或者或者 p1=0; p2=0; 此时指针此时指针p1、p2不指向任何变量,也不保存任何变量的地址。不指向任何变量,也不保存任何变量的地址。 从从图图上上看看,虽虽然然p1、p2、p3都都未未指指向向任任何何变变量量,但但p1、p2已已经经有有自自己己的的数数值值NULL,所所以以它它们们的的箭箭头头都都未未画画出出,此此时时p1、p2就相当于指向自己。就相当于指向自己。p3 而而p3既没有数据既没有数据NULL或或0,也没有指向一个变量,也没有指向一个变量p100p28.1 指针和指针变量指针和指针变量指针变量的说明指针变量的说明 指针变量的定义方式如下:指针变量的定义方式如下:306a307xint *p1;float *p2;int a;float x;p100C+是这样给是这样给p1、p2分配单元分配单元p2,*p3;.p1=&a; p2=&x;p1=NULL; p2=NULL; 或者或者 p1=0; p2=0; 此时此时,如果算法中有以下语句,如果算法中有以下语句,p3 *p1=5; *p2=5.0; *p3=6; 错错误误的的,因因为为*p1、*p2、*p3在在算算法法中中是是代代表表被被指指向向的的变变量单元,当其没有指向任何单元时,是不能存放数据的。量单元,当其没有指向任何单元时,是不能存放数据的。8.1 指针和指针变量指针和指针变量指针变量的说明指针变量的说明1.赋值运算(已介绍)赋值运算(已介绍)2. 算术运算算术运算3.关系运算关系运算8.1 指针和指针变量指针和指针变量-指针指针可执行的运算可执行的运算 2. 算术运算算术运算 指指针针的的算算术术运运算算是是变变量量寻寻址址的的一一种种非非常常重重要要的的方方法法。在在介介绍绍算算术术运算之前,有必要先了解系统分配资源的情况,设有以下说明:运算之前,有必要先了解系统分配资源的情况,设有以下说明: int i=10,j=20; char c3=“abc”; int a5=1,2,3,4,5;661855266185536618554661855520jjiC0C1C2a0a1a2a3a4编译时,系统分配资源的情况编译时,系统分配资源的情况标识符标识符 地址码地址码可以看出,可以看出,同一个程序中同一个程序中变量地址是连续排列的变量地址是连续排列的。相相差差4注意:注意:一个整数单元占一个整数单元占4个字节个字节的地址,即的地址,即6618556 106618552 206618560a6618561b6618562c6618563166185672661857136618575466185795内容区内容区8.1 指针和指针变量指针和指针变量指针变量的运算指针变量的运算66185636618564661856566185661a0数组数组a也是整型,所以,也是整型,所以,它每个元素的地址也占它每个元素的地址也占4个字节个字节 指指针针的的算算术术运运算算是是寻寻找找变变量量地地址址的的一一种种非非常常重重要要的的方方法法。在在介介绍绍算算术术运运算算之之前前,有有必必要要先先了了解解系系统统分分配配资资源源的的情情况况,设有以下说明:设有以下说明: 2. 算术运算算术运算6618556661856066185616618562661856366185676618571661857566185796618552jiC0C1C2a0a1a2a3a4标识符标识符 地址码地址码 内容区内容区 int i=10,j=20; char c3=“abc”; int a5=1,2,3,4,5;1020abc123458.1 指针和指针变量指针和指针变量指针变量的运算指针变量的运算数组数组c是字符型,是字符型,它每个元素的地址只占它每个元素的地址只占1个字节个字节 指指针针的的算算术术运运算算是是寻寻找找变变量量地地址址的的一一种种非非常常重重要要的的方方法法。在在介介绍绍算算术术运运算算之之前前,有有必必要要先先了了解解系系统统分分配配资资源源的的情情况况,设有以下说明:设有以下说明: 2. 算术运算算术运算6618556661856066185616618562661856366185676618571661857566185796618552jiC0C1C2a0a1a2a3a4标识符标识符 地址码地址码 内容区内容区 int i=10,j=20; char c3=“abc”; int a5=1,2,3,4,5;此外,变量此外,变量j的代码在的代码在i之前,之前,这是编译器的处理方法。这是编译器的处理方法。在同一个说明语句中,有的编译器在同一个说明语句中,有的编译器按从左到右,有的则从右到左。按从左到右,有的则从右到左。不同的编译器有不同的处理方法,不同的编译器有不同的处理方法,不必死记。不必死记。1020abc123458.1 指针和指针变量指针和指针变量指针变量的运算指针变量的运算 这这是是把把变变量量和和元元素素的的首地址首地址存入指针。存入指针。a0、c0是两个数组的是两个数组的首地址首地址 如果再定义以下指针变量,如果再定义以下指针变量, 然后有执行语句,然后有执行语句, 2. 算术运算算术运算6618556661856066185616618562661856366185676618571661857566185796618552jiC0C1C2a0a1a2a3a4标识符标识符 地址码地址码 内容区内容区 int i=10,j=20; char c3=“abc”; int a5=1,2,3,4,5;pc6618552,*p1,*p2;,*pc;p1p266185636618560p1=&j; p2=&a0; pc=&c0;1020abc123458.1 指针和指针变量指针和指针变量指针变量的运算指针变量的运算 2. 算术运算算术运算6618556661856066185616618562661856366185676618571661857566185796618552jiC0C1C2a0a1a2a3a4标识符标识符 地址码地址码 内容区内容区 int i=10,j=20; char c3=“abc”; int a5=1,2,3,4,5;pc6618552,*p1,*p2;,*pc;p1p266185636618560p1=&j; p2=&a0; pc=&c0; 若此后还有以下语句,若此后还有以下语句,p1+; p2+; pc+; 当执行当执行p1+时,时, 因因为为变变量量i与与j同同类类型型,所以就依次寻找到变量所以就依次寻找到变量i的地址。的地址。1020abc123458.1 指针和指针变量指针和指针变量指针变量的运算指针变量的运算 2. 算术运算算术运算6618556661856066185616618562661856366185676618571661857566185796618552jiC0C1C2a0a1a2a3a4标识符标识符 地址码地址码 内容区内容区 int i=10,j=20; char c3=“abc”; int a5=1,2,3,4,5;pc6618552,*p1,*p2;,*pc;p1p266185636618560p1=&j; p2=&a0; pc=&c0;p1+; p2+; pc+; 若此后还有以下语句,若此后还有以下语句, 当执行当执行p1+时,时, 因因为为变变量量i与与j同同类类型型,所以就依次寻找到变量所以就依次寻找到变量i的地址。的地址。66185561020abc123458.1 指针和指针变量指针和指针变量指针变量的运算指针变量的运算 2. 算术运算算术运算6618556661856066185616618562661856366185676618571661857566185796618552jiC0C1C2a0a1a2a3a4标识符标识符 地址码地址码 内容区内容区 int i=10,j=20; char c3=“abc”; int a5=1,2,3,4,5;pc6618552,*p1,*p2;,*pc;p1p266185636618560p1=&j; p2=&a0; pc=&c0;p1+; p2+; pc+; 为为什什么么p1+的的结结果果是是6618556呢呢而而不不是是6618553?这这就就是是地地址运算的特点,因为址运算的特点,因为p1+找的是下一个变量的找的是下一个变量的首地址!首地址!66185561020abc123458.1 指针和指针变量指针和指针变量指针变量的运算指针变量的运算 2. 算术运算算术运算6618556661856066185616618562661856366185676618571661857566185796618552jiC0C1C2a0a1a2a3a4标识符标识符 地址码地址码 内容区内容区 int i=10,j=20; char c3=“abc”; int a5=1,2,3,4,5;pc6618552,*p1,*p2;,*pc;p1p266185636618560p1=&j; p2=&a0; pc=&c0;p1+; p2+; pc+; 显显然然,当当执执行行语语句句p2+和和pc+时时,它它们们找找的的分分别别是是下下一一个个元元素素的的首地址!首地址!即即66185561020abc123458.1 指针和指针变量指针和指针变量指针变量的运算指针变量的运算 2. 算术运算算术运算6618556661856066185616618562661856366185676618571661857566185796618552jiC0C1C2a0a1a2a3a4标识符标识符 地址码地址码 内容区内容区 int i=10,j=20; char c3=“abc”; int a5=1,2,3,4,5;pc6618552,*p1,*p2;,*pc;p1p266185636618560p1=&j; p2=&a0; pc=&c0;p1+; p2+; pc+; 显显然然,当当执执行行语语句句p2+和和pc+时时,它它们们找找的的分分别别是是下下一一个个元元素素的的首地址!首地址!即即661855666185611020abc123458.1 指针和指针变量指针和指针变量指针变量的运算指针变量的运算 2. 算术运算算术运算6618556661856066185616618562661856366185676618571661857566185796618552jiC0C1C2a0a1a2a3a4标识符标识符 地址码地址码 内容区内容区 int i=10,j=20; char c3=“abc”; int a5=1,2,3,4,5;6618552,*p1,*p2;,*pc;p1p26618563p1=&j; p2=&a0; pc=&c0;p1+; p2+; pc+; 显显然然,当当执执行行语语句句p2+和和pc+时时,它它们们找找的的分分别别是是下下一一个个元元素素的的首地址!首地址!即即66185566618567pc661856066185611020abc123458.1 指针和指针变量指针和指针变量指针变量的运算指针变量的运算 其执行结果是其执行结果是 2. 算术运算算术运算6618556661856066185616618562661856366185676618571661857566185796618552jiC0C1C2a0a1a2a3a4标识符标识符 地址码地址码 内容区内容区 int i=10,j=20; char c3=“abc”; int a5=1,2,3,4,5;6618552,*p1,*p2;,*pc;p1p26618563p1=&j; p2=&a0; pc=&c0;p1+; p2+; pc+; 如果不用如果不用+运算符,例如将运算符,例如将p2+改成改成p2+4呢?呢?66185566618567pc66185606618561p2=p2+4;1020abc123458.1 指针和指针变量指针和指针变量指针变量的运算指针变量的运算 2. 算术运算算术运算6618556661856066185616618562661856366185676618571661857566185796618552jiC0C1C2a0a1a2a3a4标识符标识符 地址码地址码 内容区内容区 int i=10,j=20; char c3=“abc”; int a5=1,2,3,4,5;6618552,*p1,*p2;,*pc;p1p26618567p1=&j; p2=&a0; pc=&c0;p1+; p2+; pc+;66185566618579pc66185606618561p2=p2+4; 其执行结果是其执行结果是 如果不用如果不用+运算符,例如将运算符,例如将p2+改成改成p2+4呢?呢?1020abc123458.1 指针和指针变量指针和指针变量指针变量的运算指针变量的运算 2. 算术运算算术运算6618556661856066185616618562661856366185676618571661857566185796618552jiC0C1C2a0a1a2a3a4标识符标识符 地址码地址码 内容区内容区 int i=10,j=20; char c3=“abc”; int a5=1,2,3,4,5;6618552,*p1,*p2;,*pc;p1p26618567p1=&j; p2=&a0; pc=&c0;p1+; p2+; pc+;66185566618579pc66185606618561p2=p2+4; 可可见见,指指针针变变量量只只对对变变量量寻寻址址,即即变变量量的的首首地地址址。完完整整的的例例题题请请阅阅读读P141142中中例例8.2,例例8.3。其其中中输输出出的的地地址址值值因因编编译译器器的的缘缘故稍有不同故稍有不同。1020abc123458.1 指针和指针变量指针和指针变量指针变量的运算指针变量的运算 那么那么 2. 算术运算算术运算p1p=p1; p1=p2; p2=p; 指针可用来交换所保存的两个变量的地址。假如有以下定义,指针可用来交换所保存的两个变量的地址。假如有以下定义,6618552j206618556i10int i=10,j=20;int *p1=&i,*p2=&j,*p; p266185566618552p1存放了存放了i的地址,的地址,p2存放了存放了j的地址,当有下列执行语句时,的地址,当有下列执行语句时,p 则,则,6618556把把i 的地址再复制到指针的地址再复制到指针p中。中。8.1 指针和指针变量指针和指针变量指针变量的运算指针变量的运算 2. 算术运算算术运算6618556p1p=p1; p1=p2; p2=p;6618552j206618556i10int i=10,j=20;int *p1=&i,*p2=&j,*p; 6618552p2 这个语句把这个语句把p2保存的变量保存的变量j的地址的复制到指针的地址的复制到指针p1中。中。p66185566618552 继续执行继续执行8.1 指针和指针变量指针和指针变量指针变量的运算指针变量的运算 2. 算术运算算术运算6618556p1p=p1; p1=p2; p2=p;6618552j206618556i10int i=10,j=20;int *p1=&i,*p2=&j,*p; 6618552p2 这个语句把这个语句把p保存的变量保存的变量i的地址复制到指针的地址复制到指针p2中。中。p66185566618552 由由此此可可见见,这这三三个个语语句句的的执执行行,交交换换了了指指针针p1、p2原原来来所所保保存存的变量地址。的变量地址。但请注意,变量但请注意,变量i、j的地址没有变化的地址没有变化。66185568.1 指针和指针变量指针和指针变量指针变量的运算指针变量的运算 3. 关系关系运算运算两两个个指指针针变变量量的的关关系系运运算算是是根根据据两两个个指指针针变变量量的的值值(无无符符号号整数)进行比较的。整数)进行比较的。通常只有同类型的指针变量进行比较才有意义。通常只有同类型的指针变量进行比较才有意义。两指针变量相等的含义是指针变量指向相同内存单元两指针变量相等的含义是指针变量指向相同内存单元两指针变量不相等的含义是指针变量指向不同内存单元两指针变量不相等的含义是指针变量指向不同内存单元8.1 指针和指针变量指针和指针变量指针变量的运算指针变量的运算指针关系运算包括指针关系运算包括 =, !=,=。学习难点:教材学习难点:教材P143“+” “-” “*” “&”优先级相同,按优先级相同,按自右向自右向左左结合。分析执行运算时的顺序结合。分析执行运算时的顺序,比较以下表达式的不比较以下表达式的不同:同:b=*p1+b=* + p1b=(*p1)+b=+*p1在下面指针与数组的关系中,请注意以上所列难点。在下面指针与数组的关系中,请注意以上所列难点。取p1当前所指单元的内容后,p1指向下一个变量。等同于b=*p1,p1+;P1指向下一个单元后,取其内容取得p1所指单元的内容加1,p1不变,该存储单元的内容改变先将p1所指单元的内容加1,再取出该单元的内容。与上稍有不同。8.1 指针和指针变量指针和指针变量指针变量的运算指针变量的运算8.2 指针指针和数组和数组指针与数组指针与数组 8.2.1. 用指针访问数组元素用指针访问数组元素void main() int a5,j,*p; p=a; for(j=0;j5;j+)*p+=j; p=&a0; for(j=0;j5;j+)cout“a”j“”*p+t; coutendl; 数组与指针有着密切联系数组与指针有着密切联系a0a1a2a3a4jp在在C+中,数组的首地址称为中,数组的首地址称为数组的指针数组的指针。它即可用。它即可用数组名数组名表示,表示,也可用第也可用第0个元素表示。例如个元素表示。例如void main() int a5,j,*p; p=a; for(j=0;j5;j+)*p+=j; p=&a0; for(j=0;j5;j+)cout“a”j“”*p+t; coutendl; 虽虽然然a不不是是指指针针变变量量,但但p=a是是合合法法语语句句,这这是是把把数数组组a的的地地址址码码拷拷贝贝到到指指针针p中中。这这说说明明数数组组名名也也是是一一个个地地址址,实实际际上上这这个个地地址址就就是数组第是数组第0个元素的地址,故称为个元素的地址,故称为数组的首地址数组的首地址。即。即a0a1a2a3a4jp0然后执行循环,先使然后执行循环,先使j初始化初始化*p&a08.2 指针指针和数组和数组指针与数组指针与数组void main() int a5,j,*p; p=a; for(j=0;j5;j+)*p+=j; p=&a0; for(j=0;j5;j+)cout“a”j“”*p+t; coutendl; 由于由于p在在+左边,故先将左边,故先将j值赋给值赋给*p,a0a1a2a3a4jp00*p然后指针然后指针p做做+运算,运算,&a08.2 指针指针和数组和数组指针与数组指针与数组void main() int a5,j,*p; p=a; for(j=0;j5;j+)*p+=j; p=&a0; for(j=0;j5;j+)cout“a”j“”*p+t; coutendl; 由于由于p在在+左边,故先将左边,故先将j值赋给值赋给*p,a0a1a2a3a4jp00*p然后指针然后指针p做做+运算,运算, 执行第二次循环,执行第二次循环,j增值。增值。1 执行循环体,执行循环体,j值赋给值赋给*p。1结果使结果使p指向下一个元素,这就是指针在数组中的寻址过程。指向下一个元素,这就是指针在数组中的寻址过程。&a18.2 指针指针和数组和数组指针与数组指针与数组void main() int a5,j,*p; p=a; for(j=0;j5;j+)*p+=j; p=&a0; for(j=0;j5;j+)cout“a”j“”*p+t; coutendl;a0a1a2a3a4jp00*p314234 因因此此,*p+=j 的的运运算算步步骤骤是是:(1)先先将将变变量量j的的值值赋赋给给*p,(2)再对指针再对指针p作作+运算运算。&a08.2 指针指针和数组和数组指针与数组指针与数组void main() int a5,j,*p; p=a; for(j=0;j5;j+)*p+=j; p=&a0; for(j=0;j5;j+)cout“a”j“”*p+t; coutendl;a0a1a2a3a4jp00*p 以下循环显然不难举一反三。该循环结束后,各元素的值是以下循环显然不难举一反三。该循环结束后,各元素的值是314234 下面来考察输出情况下面来考察输出情况&a48.2 指针指针和数组和数组指针与数组指针与数组void main() int a5,j,*p; p=a; for(j=0;j5;j+)*p+=j; p=&a0; for(j=0;j5;j+)cout“a”j“”*p+t; coutendl;a0a1a2a3a4jp00*p 分分析析上上述述过过程程可可知知,算算法法中中的的*p是是表表示示指指针针所所指指的的单单元元,p+是在依次访问下一个存储单元是在依次访问下一个存储单元。314234 这是让指针这是让指针p回到(重新指向)数组的首地址回到(重新指向)数组的首地址&a0依次输出数组中的每个元素依次输出数组中的每个元素8.2 指针指针和数组和数组指针与数组指针与数组void main() int a5,j,*p; p=a; for(j=0;j5;j+)*p+=j; p=&a0; for(j=0;j5;j+)cout“a”j“”*p+t; coutendl;a0a1a2a3a4jp00*p314234依次输出数组中的每个元素依次输出数组中的每个元素 这这就就是是说说,*p+的的+运运算算,其其对对象象不不是是指指针针p所所指指的的单单元元*p,而而是指针是指针p本身本身。&a08.2 指针指针和数组和数组指针与数组指针与数组void main() int a3,i,*p; p=&a0; for(i=0;i3;i+)*p+=i; 下面来分析指针与数组的关系。下面来分析指针与数组的关系。a0a1a201p2 i=2时时,p做做+运运算算的的结结果果是是指指向向下下一一个个单单元元,由由于于数数组组元元素素到到a2结结束束。那那么么,p此此时时指指向向谁谁呢呢?本本程程序序的的算算法法此此时时不不知知到到下下一一个单元个单元是谁是谁? 那么,那么,C+是否是否会指出会指出本例中的本例中的数组越界呢?数组越界呢? 假如定义了假如定义了4个元素,此时个元素,此时p必然指向必然指向a3。 回回顾顾指指针针寻寻址址的的关关系系可可知知,p+是是指指针针根根据据单单元元地地址址在在内内存存中中排排列列的的顺顺序序依依次次寻寻访访单单元元。因因此此,C+认认为为上上述述下下一一个个单单元元是是内内存存中中与与a2相邻的单元。故不认为有错相邻的单元。故不认为有错。8.2 指针指针和数组和数组指针与数组指针与数组void main() int a3,i,*p; p=&a0; for(i=0;i3;i+)*p+=i; 下面来分析指针与数组的关系。下面来分析指针与数组的关系。a0a1a201p2? 虽虽然然在在算算法法中中*p是是代代表表指指针针所所指指的的那那个个单单元元的的内内容容,但但在在做做*p+时时,+运运算算的的对对象象是是指指针针p,即即其其中中的的地地址址做做+运运算算,而不是而不是*p做做+运算。运算。 尽尽管管算算法法设设计计者者不不知知到到下下一一个个单单元元是是谁谁,但但只只要要内内存存中中的的单单元没有用完,元没有用完,C+就会将一个与就会将一个与a2相邻的单元地址赋给它。相邻的单元地址赋给它。 此例中此例中*p+=i的的这种动态的运算关系请务必熟练掌握!这种动态的运算关系请务必熟练掌握!8.2 指针指针和数组和数组指针与数组指针与数组 再看本例的输出关系。再看本例的输出关系。a0a1a2012*p 执执行行p=a与与p=&a0的的结结果果完完全全相相同同。这这个个算算法法的的目目的的是是,让让指指针重新指向数组的第一个元素。针重新指向数组的第一个元素。p 这这样样,在在下下面面的的循循环环语语句句中中,就就可可从从第第一一个个元元素素开开始始,依依次次输输出出所有所有元素的数据。元素的数据。void main() int a3,i,*p; . p=a; for(i=0;i3;i+)cout*p+;&a08.2 指针指针和数组和数组指针与数组指针与数组8.2 指针指针与数组与数组指针与数组的关系指针与数组的关系void main() int a3,i,*p; . p=a; for(i=0;i3;i+)cout*p+;a0a1a2012 执执行行p=a;的的结结果果是是:p指指向向第第0个个元元素素。如如果果此此时时有有表表达达式式p+1,那么,那么,p指向哪个元素?指向哪个元素?*p 显显然然,p+2的的运运算算结结果果应应是是a2的的地地址址,而而p+i的的结结果果则则是是第第i个元素的地址。个元素的地址。p 那么那么p+1所得结果应是所得结果应是a1的地址。的地址。 如果把输出语句中的如果把输出语句中的*p+改成改成*(p+i),结果如何?,结果如何?*(p+i);&a0void main() int a3,i,*p; . p=a; for(i=0;i3;i+)cout*p+;a0a1a2012*(p+i);*pp*(p+1) 如果把输出语句中的如果把输出语句中的*p+改成改成*(p+i),结果如何?,结果如何? 根据依次寻址原则,当根据依次寻址原则,当i取取0值时值时*(p+i)是是a0这个元素。这个元素。 当当i取取1值时,值时,*(p+i)应是应是a1这个元素。这个元素。 当当i取取2值时,值时,*(p+i)应是应是a2这个元素。这个元素。*(p+2) 显然,显然,*(p+i)与与*p+的输出结果完全相同!的输出结果完全相同!&a08.2 指针指针与数组与数组指针与数组的关系指针与数组的关系void main() int a3,i,*p; . p=a; for(i=0;i3;i+)cout*p+;a0a1a2012*p 但是,但是,*(p+i)与与*p+的性质却不一样!的性质却不一样! 因为:因为:*(p+i); 执执行行(p+i)的的结结果果只只是是访访问问与与p相相距距为为i的的那那个个单单元元的的地地址址码码。而而指指针针p中中的的地地址址码码并并没没有有改改变变。本本例例中中,即即使使循循环环结结束束,p仍仍然然保保存存a0的地址码的地址码,即,始终,即,始终指向指向a0。 p+类类似似于于赋赋值值语语句句:p=p+1,执执行行p+后后,指指针针p中中的的地地址址码码就就被改变。即,被改变。即,指向指向下一个单元。下一个单元。p*(p+1)*(p+2)&a08.2 指针指针与数组与数组指针与数组的关系指针与数组的关系void main() int a3,i,*p; . p=a; for(i=0;i3;i+)cout*(p+i);a0a1a2012*p 由由于于数数组组名名也也是是指指针针,它它保保存存了了数数组组的的首首地地址址。本本例例中中就就是是a0的地址。因此,的地址。因此,p=a就是把就是把a的值的值&a0赋给指针赋给指针p。 既然如此,把既然如此,把*(p+i)改成改成*(a+i),那么,当那么,当i取取1值时即为值时即为a1.*(a+i);pa 因此,因此,*p+、*(p+i)以及以及*(a+i)的的输出结果完全相同!输出结果完全相同!*a&a0&a0但是,不能使用但是,不能使用*a+来替换来替换*p+!8.2 指针指针与数组与数组指针与数组的关系指针与数组的关系void main() int a3,i,*p; . p=a; for(i=0;i3;i+)cout*(p+i);a0a1a2012*p 因因为为,数数组组名名不不是是指指针针变变量量。编编译译器器并并不不为为数数组组名名分分配配内内存存空空间间,数组名恒等于第一个元素的地址数组名恒等于第一个元素的地址&a0 。*(a+i);pa 因因此此,诸诸如如:a=p; a+; a- 等等这这些些导导致致地地址址码码发发生生变变化化的的运算都是运算都是C+不允许的。不允许的。*a 这这说说明明,一一维维数数组组的的数数组组名名只只是是一一个个代代表表确确定定地地址址的的指指针针。这这个个地址就是地址就是&a0,在数组定义时就已经确定,在数组定义时就已经确定,在算法中不可改变在算法中不可改变。&a0&a08.2 指针指针与数组与数组指针与数组的关系指针与数组的关系void main() int a3,i,*p; . p=a; for(i=0;i3;i+)cout*(p+i);a0a1a2012*p本本例例中中,用用*(p+i)或或者者*(a+i)代代替替*p+,所所得得输输出出结结果果完完全全相同相同,这是控制变量,这是控制变量i从从0开始的效果。开始的效果。*(a+i);pa*a&a0&a08.2 指针指针与数组与数组指针与数组的关系指针与数组的关系void main() int a3,i,*p; . p=a; for(i=0;i3;i+)cout*(p+i);a0a1a2012*p 执执行行p=a;或或者者p=&a0后后,既既然然可可用用*p代代替替p所所指指的的那那个个元元素素,那么,能否用那么,能否用指针变量名指针变量名去代替数组名呢?去代替数组名呢?pi; 只只要要先先执执行行了了p=a;或或者者p=&a0,C+就就允允许许用用pi当当作作数数组组元素元素代替代替ai,此时两者,此时两者的作用的作用完全相同,即完全相同,即 实实际际上上,当当p指指向向第第一一个个元元素素时时,指指针针就就可可根根据据顺顺序序寻寻址址的的原原则则依次访问各个元素。其运算效率还比用依次访问各个元素。其运算效率还比用ai的效率高。的效率高。pa*a&a0&a08.2 指针指针与数组与数组指针与数组的关系指针与数组的关系 第第8章章 指针指针指针与数组指针与数组 关关于于各各种种等等价价形形式式,请请阅阅读读P145例例题题8.5下下面面的的描描述述以及以及P146中的三点归纳。中的三点归纳。ai, *(a+i), *(p+i), pi, *&ai下次课学习多维数组与指针作业:9-1已知:一维数组a10=1,3,5,7,9,11,13,17,19,21,请用四种方式输出每个元素的值和地址。
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号