第8章指针指针是C语言的一个重要特色;正确而灵活地运用指针可以:有效表示复杂的数据结构;能动态分配内存;方便地使用字符串;有效而方便地使用数组;在调用函数时能获得1个以上的结果;能直接处理内存单元的地址可以使程序简洁、紧凑、高效关于指针由内存单元组成,每个单元有地址,存放一字节数据内存储器000000011111010013A613A513A7shortinta;变量aa=500;内存地址是二进制数,通常写成十六进制内存地址──内存中存储单元的编号计算机内存由大量存储单元(memoryunit)组成。每个存储单元容量为1字节(byte)。每个存储单元有编号,即存储单元的“地址”(address)。存储单元中可存放数据(data)。变量的地址定义变量时,系统分配给变量的内存单元的起始地址变量值的存取通过变量在内存中的地址进行变量的地址称为“指针”(pointer)(1)直接访问──直接利用变量的地址进行存取例:shortinta;//分配内存地址a=500;在符号表中检索变量名a,找到其起始地址(例如13A6);将数值500(的二进制形式)送到内存单元13A6和13A7中变量的访问方式(2)间接访问──通过指针变量访问变量地址定义一种特殊的变量,用来存放其它变量的地址(指针),这种变量称为指针变量,它指向一个普通的变量。变量的访问方式指针变量的定义和调用inta;int*a_pointer;a=500;a_pointer=&a;printf(%d\n,*a_pointer);printf(%x\n,a_pointer);*a_pointer=3;定义一个指针变量它指向一个整型变量(基类型)给指针变量赋值指针变量的值是另一个变量的地址指针变量所指向的变量即a的值指针变量的值,即a的地址对指向的变量(即a)赋值例:73页输出格式两个指针变量交换了它们的值,也就是交换了指向intmain(){intn1,n2;int*n1_p=&n1,*n2_p=&n2,*pointer;printf(Inputn1:);scanf(%d,n1_p);printf(Inputn2:);scanf(%d,n2_p);printf(n1=%d,n2=%d\n,n1,n2);printf(*n1_p=%d,*n2_p=%d\n,*n1_p,*n2_p);printf(n1_p=%o,n2_p=%o\n,n1_p,n2_p);pointer=n1_p;n1_p=n2_p;n2_p=pointer;printf(n1=%d,n2=%d\n,n1,n2);printf(*n1_p=%d,*n2_p=%d\n,*n1_p,*n2_p);printf(n1_p=%o,n2_p=%o\n,n1_p,n2_p);}例.分析以下程序运行结果开始时指针变量n1_p指向n1,指针变量n2_p指向n2。变量n1和n2的值并没有改变,但n1_p和n2_p的值改变了,也就是指向改变了。指针变量n1_p指向n2,指针变量n2_p指向n1。上页代码要点内存内存单元内存单元的地址变量的首地址指针指针变量指针变量的指向直接访问与间接访问掌握几个重要概念区别两个*pint*p;p=&a;*p=3;指针变量的重要作用之一——作为函数的参数,实现地址传递intmain(){voidswap(intp1,intp2);inta,b;scanf(%d,%d,&a,&b);if(ab)swap(a,b);printf(%d,%d\n,a,b);return0;}例函数调用中的值传递voidswap(intp1,intp2){intp;p=p1;p1=p2;p2=p;}运行结果:a,b没有交换。原因:C语言中,实参向形参传递数据采用“值传递”,形参单独占用内存单元,交换对实参无影响。voidswap(int*p1,int*p2){intp;p=*p1;*p1=*p2;*p2=p;}例通过指针变量实现地址传递的效果注意这两个*p1的含义不同,前者说明p1为指针变量,后者表示p1所指向的变量。intmain(){voidswap(int*p1,int*p2);inta,b;int*a_p=&a,*b_p=&b;scanf(%d,%d,&a,&b);if(ab)swap(a_p,b_p);printf(%d,%d\n,a,b);return0;}p是普通的变量指针变量作为函数的参数指针作实参,对应的形参是指针变量。C语言的参数传递是“值传递”。指针变量做参数时,由于其值为变量的地址,产生“地址传递”的效果。数组做函数的参数时,也是“地址传递”。被调用函数不能改变实参指针变量的值,但可以改变实参指针变量所指向的变量的值。指针变量阅读例8.2-例8.5,上机调试,观察结果,分析掌握。要求能够熟练地掌握指针变量及其指向的变化过程,能够在纸上画图表达分析过程。访问数组——指针的又一重要用途shortinta[3];200020022004a[0]a[1]a[2]元素的地址数组元素元素的值0000000000000110a[2]=6;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx元素的地址数组的首地址数组和指针的相关概念数组的指针:数组在内存中的起始地址,即首元素(下标为0的元素)的首地址数组元素的指针:数组元素在内存中的起始地址数组名:代表数组首元素的地址(指针)指向数组的指针变量:存储数组某个元素的地址,即指向某个元素定义指向数组的指针变量intarray[5],*pointer=array;intarray[5],*pointer;pointer=array;intarray[5],*pointer=&array[0];使用指针访问数组元素,能使目标程序占用内存少、运行速度快。通过指针引用数组元素例intmain(){inta[5]={12,6,18,23,9};int*p;p=a;printf(%d,%x\n,*p,p);printf(%d,%x\n,*(p+2),p+2);p++;printf(%d,%x\n,*p,p);p=p+2;printf(%d,%x\n,*p,p);return0;}通过指针引用数组元素对于数组a和指向该数组首元素的指针变量pp+i和a+i均表示元素a[i]的地址*(p+i),*(a+i),a[i]均表示元素a[i]的值p+1的含义是指向下一个元素地址可以p++,不能a++——首元素地址不能改变注意区别*p++(等价于*(p++)),*(++p)和(*p)++(P.236-237)若定义数组a[5]和指针变量*p=a,则a[6]等价于p+6,指针指向数组之后的地址,故不报错参见P.378运算符的优先级与结合性通过指针引用数组元素例教材P.233-234例8.6三种表达方式P.235例8.7——不能达到目的数组名作为函数的参数进一步分析——用指针访问数组实参形参数组名数组名数组名指针变量指针变量指针变量指针变量数组名数组名指针变量数组名作为函数的参数—以指针表示P.239例8.8数组元素逆序排列——形参:数组名;实参:数组名P.241例8.8程序修改——形参:指针变量P.242例8.9数组元素逆序排列——形参:指针变量;实参:指针变量P.244例8.10选择排序——形参:数组;实参:指针变量P.245例8.10函数修改——形参:指针变量多维数组的指针——以二维数组为例例:声明数组inta[3][4]a[0][0]a[0][1]a[0][2]a[0][3]a[1][0]a[1][1]a[1][2]a[1][3]a[2][0]a[2][1]a[2][2]a[2][3]a=&a[0][0]=a[0]a+1=&a[1][0]=a[1]a+2=&a[2][0]=a[2]二维数组的行指针:以二维数组名表示多维数组的指针——以二维数组为例例:声明数组inta[3][4]a[0][0]a[0][1]a[0][2]a[0][3]a[1][0]a[1][1]a[1][2]a[1][3]a[2][0]a[2][1]a[2][2]a[2][3]二维数组的行指针:以二维数组名表示int*p=a;p=a+1;p=a+2;p=a[0][0]p=a[1][0]p=a[2][0]多维数组的指针——以二维数组为例例:声明数组inta[3][4]a[0][0]a[0][1]a[0][2]a[0][3]a[1][0]a[1][1]a[1][2]a[1][3]a[2][0]a[2][1]a[2][2]a[2][3]a[0]=&a[0][0]a[0]+1=&a[0][1]a[1]+2=&a[1][2]a[0]+5=&a[1][1]二维数组的列指针:以一维数组名表示多维数组的指针——以二维数组为例例:声明数组inta[3][4]a[0][0]a[0][1]a[0][2]a[0][3]a[1][0]a[1][1]a[1][2]a[1][3]a[2][0]a[2][1]a[2][2]a[2][3]二维数组的列指针:以指针变量表示int*p;p=a;p++;p=p+5;p=a[0][0]p=a[0][1]p=a[1][2]通过指针引用字符串字符串是在内存中连续存放的一组字符以变量形式保存字符串需要声明字符数组或声明一个指针变量访问字符串或字符数组(P.257图8.28)——不是字符串变量char*string;string=Workhard!;printf(%s\n,string);printf(%c\n,*string++);printf(%c\n,*(string+5));printf(%s\n,string);++在后,先取p值,再++,p用于*p请对照*(++p)通过指针引用字符串P.255例8.16使用字符数组存放字符串使用字符数组名输出字符串使用字符数组下标访问数组元素通过指针引用字符串P.256例8.17使用基类型为字符的指针变量保存字符串首元素地址,从而访问字符串char*p=China;printf(%s,p);P.256例8.18数组名指针的应用(字符型)P.256例8.19指针变量访问字符型数组相当于char*p;p=China;而不是char*p;*p=China;通过指针引用字符串字符指针作函数参数实参形参数组名数组名数组名指针变量指针变量指针变量指针变量数组名P.259-263例8.20各种不同的表达方式8.4.3节分析一些容易发生的错误指向函数的指针——指向函数代码的起始地址。若声明一个指针变量存放该地址,则可通过此指针变量来调用该函数。例:P.267改写的代码作用:可用同样的语句调用不同函数定义一个以指向函数的指针变量作为形参的函数,可写出复杂程序(P.271例8.24和P.273分析)返回指针值的函数一个函数,其运算结果和返回值是指针值P.274例8.25P.275例8.26指针数组和多重指针指针数组是存放指针数据的数组指向上述数组的指针——指向指针数据的指针在操作系统下调用C语言程序时,如果要向C程序传递数据,可使用带参数的main函数,其形参是指针数组动态内存分配与指向它的指针变量关于内存地址分配,参见7.9节。全局变量/静态变量:保存在静态存储区。声明时分配存储空间,文件运行结束时释放。自动变量:声明时动态地分配存储空间,函数运行结束时释放。——栈存储区一些临时数据可在使用时动态地分配存储单元,使用结束立即释放。——堆存储区,只能用指针访问。动态内存分配与指向它的指针变量内存动态分配库函数(stdlib.h)(1)malloc(size)分配size字节的存储空间(2)calloc(n,size)分配n个size字节的连续空间(3)free(p)释放指针变量p占用的动态空间(4)realloc(p,size)改变指针变量p指向的空间大小函数(1)(2)(4)返回void基类型的指针