新编C语言程序设计教程PPT第9章指针.ppt
新编C语言程序设计教程 清华大学出版社,周二强 软件学院 计算机科学与工程系配套视频:博客:,第9章 指针,9.4 指针变量的运算9.4.1 指针支持的运算9.4.2 表达式的左值性和右值性9.5 指针与数组 9.5.1 指针与一维数组9.5.2 指针和二维数组9.5.3 指针与字符串,9.4.1 指针支持的运算,指针变量可以与一个整数做加法或减法运算。如果一个整型指针变量pi的右值为0 x0012 ff00,则pi+1的值是多少呢?做加法运算时变量pi应表现为右值0 x0012 ff00,但是pi+1的结果不是0 x0012 ff01!指针变量指向的是存储单元,其值0 x0012 ff00仅是存储单元的首地址,pi+1的结果也为指针变量且指向后面相邻的整型存储单元,因此新的指针变量的右值为0 x0012 ff04,其类型与指针变量pi的相同。,例9-10 分析下面程序的输出,例9-11,设指针变量p的右值为0 x0012 ff00,求其定义如下时p+1的右值。1.char*p;2.char(*p)51.指针变量p所指向的存储单元为字符型,故p+1的右值为0 x0012 ff01,相关存储单元的类型也为字符型。2.char(*p)5定义中先解释*p,故变量p为指针变量,其类型为char 5,即长度为5的字符型数组,因此,p+1的右值为0 x0012 ff05,相关存储单元的类型也是长度为5的字符型数组。,char*p 5相当于char*(p 5),先解释p 5,定义一个长度为5的数组p,数组元素的类型为char*即字符型指针。,指针变量的减法,与加法相同,p-1的结果为指向前面相邻的存储单元的指针变量,其右值为相关存储单元的首地址,类型也与变量p的相同。两个同类型的指针变量可以相减,结果为整数,表示两个变量之间相差几个同样的存储单元。对于图9-5的指针变量p,(p+2)p的值为2。p+2的值为a2的地址0 x0012 ff10,p的值为0 x0012 ff00,两者相差2个存储单元(double类型共16个字节)。,指针变量的运算,对于指针变量p,p=p+1;同样可简写为p+=1;或+p;、p+;。p=p 1;与此类似。两个同类型的指针变量可以进行等于(=)或不等于(!=)比较运算,如果两个指针变量相等,则它们指向同一块存储单元。两个同类型的指针变量也可以进行、=和=比较运算。指针变量的运算通常与数组相关时才有实际意义。,pi+1的左值,pi+1的结果为指向后面相邻的一个类型相同的存储单元的指针变量,其右值为0 x0012 ff04,但其左值,运算器中的存储单元,pi+1的计算在运算器中进行,计算结果也位于运算器中。运算器中的存储单元仅供运算器使用,应用程序只能读其中的内容而不能写入数据。表示pi+1的结果的指针变量可理解为一个无名临时变量。与无名临时变量相关的存储单元多位于运算器中。强制类型转换的结果、C语言中许多表达式的结果均可理解为无名临时变量。无名临时变量的特点是程序只能读取其值而不能写入数据。,赋值语句pi+1=3;,以赋值语句pi+1=3;为例,该语句先进行pi+1的操作,此时变量pi虽然在赋值操作符的左边,但要进行加法运算,变量pi表现为右值,运算结果如图所示的无名临时变量。应用程序不能使用无名临时变量的左值向其写入数据,因此语句pi+1=3;不可能把整数3存入相关存储单元,也就是说该语句非法!,return,表达式的左值性或右值性,具有左值性的表达式可以位于赋值操作符的左边,而具有右值性的表达式只能位于赋值操作符的右边。表达式pi+1就具有右值性而不具有左值性。C语言中许多表达式的结果均为无名临时变量,因此可以简单地把表达式的左值性问题归结为与无名临时变量相关的地址是否可以被应用程序写入的问题。如果与无名临时变量相关的地址不允许程序写入,则相关的表达式就表现为右值性。显然大部分C语言表达式表现为右值性。,例9-12,相关变量的内存状态如图9-6(1)所示,判断表达式*(pi+1)和*(的语句可以正常执行,表达式*(pi+1)为左值性。,判断表达式*(&i)是否表现为左值性,的语句可以正常执行,表达式*(&i)为左值性。,return,9.5 指针与数组,在C语言中,指针与数组有着密切的关系,这种关系表现在对数组元素的引用可以改写成对指针的间接引用。有数组a,则ae1与*(a+e1)等价;有指针变量p,则*(p+e1)与pe1等价。C语言规定:数组变量(a)的右值为数组首元素的地址(&a0)。,9.5.1 指针与一维数组,例9-13 已知int a3=1,2,3;如何理解数组a?,分析表达式sizeof(a)a=3sizeof(a+1)*a+1*(a+1),pi=a;pi=a是把数组变量a的右值存储到指针变量pi相关的储存单元中。数组变量a的右值为a0的地址,故pi=a相当于pi=&a0,即pi指向了整型变量a0。pi=a后,分析表达式pi+、*pi+、*+pi和pi2。,例9-13 已知int a3=1,2,3;int*pi;。,例9-14 分析程序,例9-15分析程序,分析程序,例9-16 分析例7-18(实参也会改变),数组间如何赋值?,数组b的值为其首元素的地址。,数组类型为形参时会退化,C语言规定,形参的类型为数组时,数组类型会退化为相应的指针类型。对于一维数组a,由于它的值为首元素a0的地址,即整型存储单元的首地址,所以函数的形参int a2或int a 退化为指向整型变量的指针,也就是说swap(int a)应理解为swap(int*a),在这里形参a不再是一个数组变量,而仅是一个普通的指针变量。在main函数中,函数调用swap(b)执行时,实参b的值为b0的地址,故此时参数a的值为b0的地址,指针变量a指向了b0。,return,9.5.2 指针和二维数组,例9-17 如何理解二维数组?以二维数组int a32=1,2,21,22,31,32为例,二维数组a有3个数组元素二维数组变量a看作一个虚拟变量,则它的存储单元长度为24个字节(sizeof(a)的值为24),它存储的内容是首元素a0的地址0 x0012 ff00,相关存储单元的类型为sizeof(*a)的值为,如何理解一维数组a0 呢?,二维数组变量a,二维数组变量a,一维数组变量a0,整型变量a00三者的关系如图,分析表达式 a,a+1,a+2,变量a为虚拟的二维数组变量 a+1中二维数组变量a表现为右值,故a+1的值为地址 同理a+2是a2的地址。,分析表达式*a,*a+1,*(a+1)+1和*a,*a与a0等价,a0为虚拟的一维数组变量*a+1中*a(a0)表现为的右值,即a00的地址0 x0012 ff00,故表达式的结果为地址0 x0012 ff04,即a01的地址。*(a+1)+1中*(a+1)与a1等价*a就是*(*a),也为*(a0),a0的值为其首元素a00的地址,故*(a0)与a00等价,有int*p=(int*)0 x0012 ff00,则表达式p=a的值是否为真。,整型指针变量p和二维数组变量a的右值均为0 x0012 ff00,但是整型指针变量p指向存储单元的类型为整型,而二维数组变量a指向的存储单元的类型为有2个元素的一维整型数组,两者类型不一致,因此两者的比较操作没有实际意义,也就是说表达式p=a有问题。p=a也是有问题的,指向有两个元素的一维整型数组的指针变量,只有指向有两个元素的一维整型数组的指针变量才能用二维数组变量a赋值。相关指针变量理想的定义方式为int2*p,而C语言中实际的定义方式为int(*p)2(注意不用int*p2定义)。定义后,就可以用p=a或p=&a0把二维数组变量a的右值保存在指针变量中。此时指针变量p、二维数组变量a、一维数组变量a0及a00的关系如图9-9所示。,return,9.5.3.1 字符串常量,C语言中字符串常用字符数组存储。一维字符数组变量的值为首元素(字符变量)的地址,因此,一维字符数组作函数参数时退化为一个指向字符型变量的指针变量,同时可以把字符数组变量赋值给字符型指针变量。,例9-20 分析下面的程序。,字符串常量hello!,字符串字面量,通常以字符数组的形式存储于内存中一个“只读”的特殊内存区域,并且整个字符串常量表现为与首字符相关的存储单元的首地址。,例9-20 分析下面的程序。,9.5.3.2 指针数组和指向指针的指针,指针数组是数组元素为指针类型的数组,如语句char*a3=C,C+,Java;就定义并初始化了一个一维的字符型指针数组,数组a的三个数组元素a0、a1和a2的类型为字符型指针。使用一维的字符型指针数组常见的错误为char*p;p=a;,即用一维的字符型指针数组变量a给字符型指针赋值。一维的字符型指针数组a可能的存储状态如图9-11所示。,p=a0;,指向存储单元类型为字符型指针的指针,可以用语句char*(*pp);或char*pp;定义一个指向存储单元类型为字符型指针的指针。如果一个指针指向的变量为指针类型,则称该指针为指向指针的指针。可以用数组变量a给指向指针的指针变量pp(char*pp;)赋值(pp=a;),赋值后指向指针的指针变量pp,数组变量a,和数组元素a0的关系如图9-12(1)所示。,指向存储单元类型为字符型指针的指针,也可用指针变量p的地址给指向指针的指针变量pp赋值(pp=&p),此时指向指针的指针变量pp,指针变量p,数组元素a0的关系如图9-12(2)所示,设变量p的地址为0 x0013 0000。,例9-21 分析程序的输出,puts(*(pp-1);,p=a1;pp=,pp=,例9-21 分析程序的输出,一维指针数组作为函数参数时,一维指针数组作为函数参数时退化为指向指针的指针。例9-22 分析程序的输出,return,