c程序设计(第四版)谭浩强第8章指针.ppt
第8章 指针,指针是C语言的一个重要特色; 正确而灵活地运用指针可以: 有效表示复杂的数据结构; 能动态分配内存; 方便地使用字符串; 有效而方便地使用数组; 在调用函数时能获得1个以上的结果; 能直接处理内存单元的地址 可以使程序简洁、紧凑、高效,关于指针,由内存单元组成,每个单元有地址,存放一字节数据,内存储器,0000000111110100,short int a;,变量a,a=500;,内存地址是二进制数,通常写成十六进制,内存地址──内存中存储单元的编号,计算机内存由大量存储单元 (memory unit)组成。每个存储单元容量为1字节(byte) 。每个存储单元有编号,即存储单元的“地址” (address) 。存储单元中可存放数据(data)。,变量的地址,定义变量时,系统分配给变量的内存单元的起始地址变量值的存取通过变量在内存中的地址进行变量的地址称为“指针”(pointer),(1)直接访问──直接利用变量的地址进行存取例:short int a; //分配内存地址a=500;在符号表中检索变量名a,找到其起始地址(例如13A6);将数值500(的二进制形式)送到内存单元13A6和13A7中,变量的访问方式,(2)间接访问──通过指针变量访问变量地址定义一种特殊的变量,用来存放其它变量的地址(指针),这种变量称为指针变量,它指向一个普通的变量。,变量的访问方式,指针变量的定义和调用,int a; int *a_pointer; a = 500; a_pointer = ,定义一个指针变量,它指向一个整型变量(基类型),给指针变量赋值,指针变量的值是 另一个变量的地址,指针变量所指向的变量即a的值,指针变量的值,即a的地址,对指向的变量(即a)赋值,例:,73页输出格式,int main() { int n1,n2; int *n1_p= },例. 分析以下程序运行结果,开始时指针变量n1_p指向n1,指针变量n2_p指向n2。 变量n1和n2的值并没有改变,但n1_p 和n2_p的值改变了,也就是指向改变了。指针变量n1_p指向n2,指针变量n2_p指向n1。,上页代码要点,内存 内存单元 内存单元的地址 变量的首地址 指针 指针变量 指针变量的指向 直接访问与间接访问,掌握几个重要概念,区别两个 *pint *p;p=,指针变量的重要作用之一 ——作为函数的参数,实现地址传递,int main() { void swap(int p1,int p2);int a,b;scanf(“%d,%d“, },例 函数调用中的值传递,void swap(int p1,int p2) { int p;p=p1; p1=p2; p2=p; },运行结果:a,b没有交换。 原因:C语言中,实参向形参传递数据采用“值传递”,形参单独占用内存单元,交换对实参无影响。,void swap(int *p1,int *p2) { int p;p=*p1; *p1=*p2; *p2=p; },例 通过指针变量实现地址传递的效果,int main() { void swap(int *p1,int *p2);int a,b;int *a_p= },p是普通的变量,指针变量作为函数的参数,指针作实参,对应的形参是指针变量。 C语言的参数传递是“值传递”。 指针变量做参数时,由于其值为变量的地址,产生“地址传递”的效果。 数组做函数的参数时,也是“地址传递”。 被调用函数不能改变实参指针变量的值,但可以改变实参指针变量所指向的变量的值。,指针变量,阅读例8.2-例8.5,上机调试,观察结果,分析掌握。 要求能够熟练地掌握指针变量及其指向的变化过程,能够在纸上画图表达分析过程。,访问数组——指针的又一重要用途,short int a[3];,元素的地址,数组元素,元素的值,0000000000000110,a[2]=6;,xxxxxxxxxxxxxxxx,xxxxxxxxxxxxxxxx,xxxxxxxxxxxxxxxx,元素的地址,数组的首地址,数组和指针的相关概念,数组的指针:数组在内存中的起始地址,即首元素(下标为0的元素)的首地址 数组元素的指针:数组元素在内存中的起始地址 数组名:代表数组首元素的地址(指针) 指向数组的指针变量:存储数组某个元素的地址,即指向某个元素,定义指向数组的指针变量,int array[5], *pointer = array;int array[5], *pointer;pointer = array; int array[5], *pointer = 使用指针访问数组元素,能使目标程序占用内存少、运行速度快。,通过指针引用数组元素,例,int main( ){ int a[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);return 0; },通过指针引用数组元素,对于数组a和指向该数组首元素的指针变量p p+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 函数修改——形参:指针变量,多维数组的指针——以二维数组为例,例:声明数组 int a[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 p=a+1; p=a+2;,p = a[0][0] p = a[1][0] p = a[2][0],多维数组的指针——以二维数组为例,例:声明数组 int a[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] 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=“Work hard!“; 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基类型的指针;(3)无返回值 使用void基类型的指针变量访问动态内存分配区 例8.30,小 结,,理解指针,能深入计算机的内存,写出面向底层的程序,使程序简洁明快。初学者首先做到理解概念,读懂例子,将一些做过的题改用指针完成,初步了解指针的概念与用法。,