第七章指针第七章指针7.1地址和指针7.2指向变量的指针变量7.3指针与函数7.4通过指针引用数组7.5字符指针和字符串7.6指针数组和多重指针指针是C语言中最具特色的内容,也是C语言的重要概念和精华所在。C语言是既具有低级语言特色又具有高级语言特色的语言,其低级语言特色的主要表现就体现在对地址的直接操作,而对地址的直接操作主要是通过指针来实现。7.1地址和指针返回7.1地址和指针计算机内存空间是由顺序排列的以字节为单位的存储单元组成的,将这些存储单元从0开始顺序编号,这些编号就构成了每个存储单元的地址。每个数据都存放于从某个特定的地址开始的若干个字节的存储单元中,计算机对数据的存取都是通过地址才得以实现的。由于地址指明了数据存储的位置。在某些类型的应用中,需要先”算出”数据的存储地址,然后再通过该地址间接的访问数据。因此形象地将地址称之为指针。指针不但标明了数据的存储位置,而且还标明了该数据的类型,可以说指针是存储特定数据类型的地址。7.1地址和指针计算机CPU对变量的访问是根据内存单元的地址来进行的。访问的方式直接访问和间接访问两种。(1)直接访问含义:已知变量的地址直接存取地址单元内的值。方法:通过变量名进行访问。如:intx=3;printf(“%d”,x);7.1地址和指针(2)间接访问含义:通过存放变量地址的变量(指针变量)来访问目标单元的值。方法:通过指针变量进行访问。指针类型指针的类型就是指针所指向的数据的类型。指针的类型限定指针的用途,例如一个double型指针只能用于指向double型数据。不限定类型的指针为无类型的指针或者说是void指针,可用于指向任何类型的数据。7.1地址和指针7.2指向变量的指针变量指针变量的定义和初始化用来存放地址的变量叫指针变量。(1)定义格式:类型标识符是指针变量所指向单元的数据类型。“*”是指针变量的定义符;如:intx,*p1;p1=&x;则p1表示x的内存地址。取地址运算符:&,用于变量名之前,表示该变量的内存地址。返回(2)指针变量的初始化即在定义变量的同时给指针变量赋地址值。如:intx=3;floaty;int*pointer1=&x;float*pointer2=&y;pointer1和pointer2为指针变量,&x和&y为x和y变量的地址。7.2指向变量的指针变量指针变量使用之前,如果没有给指针变量赋值,即指针变量没有指向一个具体的地址,这样的指针叫空指针,空指针是”危险”的。因此如果指针变量暂时不指向一个变量地址,请给指针变量赋NULL值。指针变量的引用指针运算符:*,又称间接访问运算符,用于指针变量名之前,获取该指针所指向的目标单元的值。7.2指向变量的指针变量”&”和”*”两个运算符的优先级别是相同的,结合规律是右结合性。指针变量的运算(1)算术运算含义:对于地址的运算,只能进行整型数据的加、减运算。规则:指针变量p+n表示将指针指向的当前位置向前或向后移动n个存储单元。指针变量的算术运算结果是改变指针的指向。7.2指向变量的指针变量指针相减通常用来计算两地址间数据单元的个数。同类型的两指针相减,其结果是一个整数,表示两地址之间可容纳的相应类型数据的个数。注意:只有高地址指针减低地址指针才有意义。(2)指针移动通过加(减)操作和加(减)赋值操作,可用使指针完成向前或向后移动。移动一个单位可用使用自增和自减运算。7.2指向变量的指针变量向后(高地址方向)移动一个单元,使用自增运算,向前(低地址方向)移动一个单元使用自减运算。7.2指向变量的指针变量(3)赋值运算作用:对指针变量的赋值运算,将改变指针变量所指向的地址。指针变量作为函数参数通过”传地址”形参指针成为实参指针的副本,于是通过形参指针也可以访问实参指针所指向的数据,因此指针参数的传递就是把实参指针所指向的数据间接的传递给被调用的函数。例子1#include“stdio.h”2voidswap(int*p1,int*p2)//用指针变量实现数据的交换3{4inttemp;7.2指向变量的指针变量5temp=*p1;6*p1=*p2;7*p2=temp;8}9voidmain(intargc,char*argv[])10{11inta,b,*pointer_1,*pointer_2;12scanf(“%d,%d”,&a,&b);13pointer_1=&a,pointer_2=&b;14if(ab)//如果ab交换两数15swap(pointer_1,pointer_2);16printf(“\n%d,%d\n”,a,b);17}7.2指向变量的指针变量输入:12,34输出:34,12说明:①指针变量作为参数,从调用函数向被调用函数传递的不是一个变量,而是变量的地址。②指针变量作为函数的参数,从实参向形参的数据传递仍然遵循”单向值传递”的原则,只不过此时传递的是地址,因此对形参的任何操作都相当于对实参的操作。从这个意义上讲指针变量作函数参数的传递又具有了”双向性”,可以带回操作后的结果。7.2指向变量的指针变量指针函数函数不但可以返回数值型数据而且还可以返回指针值,能够返回指针值的函数叫指针函数。指针函数定义格式如下:7.3指针与函数①定义指针函数时,函数名前必须有*。②返回的是一个指针值,而不是一个数值型数据。返回注意,指针函数所返回的指针不能是函数返回后即不存在的对象,如函数中的自动变量,形参变量等。函数指针指针可以指向变量、可以指向数组也可以指向函数,指向函数的指针称为函数指针。C语言函数名实质上也是地址,即函数的入口地址。因此可以用一个指针变量来指向这个地址,把这个指向函数入口地址的指针叫做函数指针,然后通过函数指针来调用指向的函数。7.3指针与函数函数指针定义如下:7.3指针与函数实际上指针变量名就相当于函数名。关于函数指针变量的几点说明:①函数指针变量是有类型的。②即函数指针不能用于计算。③函数指针变量的优点是提供了一种将函数作为形参的机制。数组的指针和数组元素的指针数组的指针是指数组的起始地址。数组元素指针是指数组元素在内存中的存放地址。指向数组和数组元素的指针变量用于存放数组的起始地址或某一数组元素地址的变量。一维数组元素的指针访问方式一维数组的数组名实际上就是指向该数组的第一个单元的指针。7.4通过指针引用数组返回若一维数组定义为:inta[10];则数组名a的类型是int*(数组名代表数组的首地址,因此是指针类型),并且指向第一个元素;因此*a和a[0]访问的是同一个元素,两种表达形式完全等价,这种指针表达形式不仅可以访问第一个元素,结合指针移动还可以访问数组的其他元素。7.4通过指针引用数组例如:*(a+1)等价于a[1];*(a+2)等价于a[2];……*(a+i)等价于a[i];因此访问数组元素的操作可以采用两种方法,一种叫下标法;一种叫指针法。采用指针法比采用下标法更为简洁,执行效率也更高。7.4通过指针引用数组例如:inta[10],*pa=a;下标法与指针法的对应关系如图所示7.4通过指针引用数组两种访问方式在形式上遵守下面的等价关系:7.4通过指针引用数组指针变量还可以用自增或自减运算来改变指针所指向的位置,达到移动指针的目的。要特别注意,数组名虽然是指针(地址),但它是指针常量而不是指针变量,因为我们不可能改变一个常量的值,所以数组名永远指向定义时与之关联的那个数组空间。想用自增或自减来改变数组名的指向是办不到的,即对指针变量的自增自减操作不能用于数组名。例7.10输出数组的全部元素(几种访问方法比较)。7.4通过指针引用数组方法一:下标法voidmain(intargc,char*argv[]){inta[5]={1,2,3,4,5};inti;for(i=0;i5;i++)printf(“%d,”,a[i]);printf(“\n”);}7.4通过指针引用数组7.4通过指针引用数组方法二:地址法voidmain(intargc,char*argv[]){inta[10]={1,2,3,4,5};inti;for(i=0;i5;i++)printf(“%d,”,*(a+i));printf(“\n”);}7.4通过指针引用数组方法三:指针法voidmain(intargc,char*argv[]){inta[10]={1,2,3,4,5};int*p;for(p=a;pa+5;p++)printf(“%d,”,*p);printf(“\n”);}三种方法的输出结果都是:1,2,3,4,57.4通过指针引用数组说明:指针变量可以实现自身值的改变。如:pa++;而数组名所代表的地址则不能改变,a++是错误的用法。应注意指针变量的当前值。指针变量可以指向数组中各个内存单元。7.4通过指针引用数组多维数组元素的指针访问方式以二维数组为例介绍多维数组的指针访问方式二维数组可以看成是一种特殊的一维数组,每一个一维数组元素本身又是一个有若干个数组元素的一维数组。例如:intb[3][4];可以看成是具有3个元素的一维数组,其中每个元素本身又是一个具有4个元素的int型一维数组。因此对于二维数组”数组名就是指向该数组第一个单元的指针”,只是”第一个单元”的含义不同。数组名b代表整个二维数组的首地址,实际上是指二维数组第0行的首地址。那么b+1代表第一行的首地址,b+2代表第二行的首地址。7.4通过指针引用数组一维数组下标与指针的等价关系也适用于二维数组。由于二维数组名表示的是二维数组行地址,要用专门的接受行地址的指针来接受行地址。行指针的定义方法,其格式为:intb[10][20],(*pb)[20]=b;7.4通过指针引用数组由于行指针与二维数组名等价,因此很容易得到计算i行j列的元素公式。7.4通过指针引用数组由于行指针与二维数组名等价,因此很容易得到计算i行j列的元素公式。例7.12设计函数show_matrix,它显示参数传来的整型二维数组。1#include“stdio.h”2voidshowMatrix(int(*array)[3],introw,intcol)//array为行指针3{4inti,j;5for(i=0;irow;i++)6{7printf(“\n”);8for(j=0;jcol;j++)9printf(“%4d”,*(*(array+i)+j));//计算地址公式变了7.4通过指针引用数组10}11}12voidmain(intargc,char*argv[])13{14ints[4][3]={1,2,3,4,5,6,7,8,9,10,11,12};15showMatrix(s,4,3);//二维数据名做实参16printf(“\n”);17}7.4通过指针引用数组数组名作函数的参数在C语言中,只能将实参数组的指针或数组元素赋值给对应的形参变量。参数传递的特点是:数组元素作函数的参数,同一般的变量一样。数组名作为函数的参数,实参与形参操作的是内存中的同一段地址单元,这样在被调用函数中对数组元素内容的修改将会反映到调用函数中。7.4通过指针引用数组数组作函数的参数时,实参与形参还可用指针的形式给出。如图所示:7.4通过指针引用数组例7.13将数组a中的n个整数按相反的顺序存放。C语言是用字符型数组来存储字符串变量的。同时,数组名代表字符串的首地址,其实任何指向字符串第一个元素的指针都可以代表该字符串。字符串的表示形式(1)用字符数组实现charstring[]=“IloveChina!“;printf(“%s\n”,string);7.5字符指针和字符串返回说明:①string是数组名,代表数组的首地址;②string[i]代表数组的第i个元素,string[i]等价于*(string+i)。③其相应的处理方法同一般数组相似。(2)用字符指针实现char*string=“IloveChina!”;printf(“%s\n”,string);7.5字符指针和字符串说明:①字符串指针:是指向字符变量的指针变量,可以用来描述和