C语言教程课件Ch10指针.ppt
本章主要内容本章主要内容指针和地址的概念指针和地址的概念指针变量指向数组指针变量指向数组/字符串时的操作字符串时的操作指针变量做函数参数指针变量做函数参数几种指针类型几种指针类型返回指针值的函数返回指针值的函数重点、难点重点、难点如何理解指针和地址的概念如何理解指针和地址的概念灵活使用指向一位数组灵活使用指向一位数组/字符串的指针字符串的指针灵活使用指针变量灵活使用指针变量/数组名做函数参数数组名做函数参数掌握几种指针的概念掌握几种指针的概念与函数一章的例题结合,掌握参数单向传递的与函数一章的例题结合,掌握参数单向传递的实质实质10.1 10.1 指针的概念指针的概念指针的概念指针的概念10.2 10.2 变量的指针和指向变量的指针变量变量的指针和指向变量的指针变量变量的指针和指向变量的指针变量变量的指针和指向变量的指针变量10.3 10.3 数组的指针和指向数组的指针变量数组的指针和指向数组的指针变量数组的指针和指向数组的指针变量数组的指针和指向数组的指针变量10.4 10.4 字符串的指针和指向字符串的指针变量字符串的指针和指向字符串的指针变量字符串的指针和指向字符串的指针变量字符串的指针和指向字符串的指针变量10.5 10.5 函数的指针和指向函数的指针变量函数的指针和指向函数的指针变量函数的指针和指向函数的指针变量函数的指针和指向函数的指针变量10.6 10.6 返回指针的函数返回指针的函数返回指针的函数返回指针的函数10.7 10.7 指针数组和指向指针的指针指针数组和指向指针的指针指针数组和指向指针的指针指针数组和指向指针的指针10.8 10.8 有关指针的数据类型和指针运算的小结有关指针的数据类型和指针运算的小结有关指针的数据类型和指针运算的小结有关指针的数据类型和指针运算的小结1地址的概念地址的概念 程序中每一个变量在编译或运行时系统都为其分配内存程序中每一个变量在编译或运行时系统都为其分配内存单元,每一个内存单元单元,每一个内存单元(字节字节)都有一个相应的编号,这个都有一个相应的编号,这个编号称为该内存单元的编号称为该内存单元的“地址地址”,而内存单元中存入的内,而内存单元中存入的内容则是该变量的值。容则是该变量的值。内存用户数据区内存用户数据区36920002000200220043010变量变量 i变量变量 j变量变量 k变量变量 i_pt10.1 10.1 指针的概念指针的概念指针的概念指针的概念int i=3,j=6,k=9;int *i_pt;i_pt=&i;指针是指针是c c语言中比较灵活的数据结构语言中比较灵活的数据结构,灵活地运用指针灵活地运用指针可以可以:(1)(1)有效地表示复杂的数据结构有效地表示复杂的数据结构.(2)(2)动态分配内存动态分配内存.(3)(3)更方便地使用字符串和数组更方便地使用字符串和数组.(4)(4)直接处理内存地址直接处理内存地址.2 2对内存单元的存取有两种方式对内存单元的存取有两种方式 (1)(1)直接访问直接访问 按按变量地址变量地址存取变量的值。存取变量的值。(2)(2)间接访问间接访问 将变量将变量i i的地址存放在另一个内存单元的地址存放在另一个内存单元j j中,要访问中,要访问i i,则先按则先按j j的地址取出的地址取出i i的地址,再按的地址,再按i i的地址取出的地址取出i i的值。的值。直接访问和间接访问示意图直接访问和间接访问示意图3i20003ii_pt 20003 3指针变量的概念指针变量的概念 一个一个变量的地址变量的地址称为该变量的称为该变量的“指针指针”。如果有一个变量专门用来存放另一个变量的地址如果有一个变量专门用来存放另一个变量的地址(即指即指针针),则它称为,则它称为“指针变量指针变量”。指针变量的值是指针。指针变量的值是指针。一、指针变量的定义一、指针变量的定义 指针变量必须在使用之前先定义,它是用来存放地址的。指针变量必须在使用之前先定义,它是用来存放地址的。必须将它定义为必须将它定义为“指针类型指针类型”。定义的一般形式为:定义的一般形式为:类型标识符类型标识符 *标识符标识符注注:(1)标识符前面的标识符前面的“*”,表示该变量为指针变量。但指针变,表示该变量为指针变量。但指针变 量名是量名是pt_1、pt_2、pt_3,而不是,而不是*pt_1、*pt_2、*pt_3。(2)*表示表示指向指向,故故*pt_1,*pt_2,*pt_3表示指针变量表示指针变量 pt_1,pt_2,pt_3所指向的变量。所指向的变量。(3)一个指针变量只能指向一个指针变量只能指向同一个类型同一个类型的变量。的变量。10.2 10.2 变量的指针和指向变量的指针变量变量的指针和指向变量的指针变量变量的指针和指向变量的指针变量变量的指针和指向变量的指针变量例例例例:int *pt_1;char *pt_2;float *pt_3;二、指针变量的引用二、指针变量的引用 有两个有关的运算符有两个有关的运算符 (1)&取地址运算符取地址运算符 (2)*指针运算符指针运算符(或称或称“间接访问间接访问”运算符运算符)。例例:int a,*pt;&a为变量为变量a的地址的地址,*pt为指针变量为指针变量pt所指向的变量所指向的变量.则则:&*pt=&a=pt 则则:*&a=*pt=a 则则:(*pt)+相当于相当于a+apt *pt若若:pt=&ab=(*pt)+;c=*pt+;b与与c值是否相等值是否相等?void main()int a,b,*p1,*p2;a=100;b=10;p1=&a;p2=&b;printf(%d,%dn,a,b);printf(%d,%dn,*p1,*p2);例例例例:1:1100,10100,10运行结果运行结果*p1ap1bp2&b*p210010&a例例2:void main()int a,b,*p1,*p2,*p;scanf(%d%d,&a,&b);p1=&a;p2=&b;if(ab)p=p1;p1=p2;p2=p;printf(%d,%dn,a,b);printf(%d,%dn,*p1,*p2);输入:输入:5 9*p1ap1bp2&b*p2 5 9&ap&b&a输出:输出:5,99,5void main()int a,b,*p1,*p2,t;scanf(%d%d,&a,&b);p1=&a;p2=&b;if(ab)t=*p1;*p1=*p2;*p2=t;printf(%d,%dn,a,b);&a*p1*p2三、指针变量作为函数参数。三、指针变量作为函数参数。例例1:输入:输入a和和b两个整数,按先大后小的顺序输出两个整数,按先大后小的顺序输出a和和b。void main()int a,b;int*point_1,*point_2;scanf(%d%d,&a,&b);point_1=&a;point_2=&b;if(ab)swap(point_1,point_2);printf(n%d,%dn,a,b);printf(n%d,%dn,*point_1,*point_2);输入数据输入数据:4 8输出结果输出结果:8,4 8,4void swap(int*p1,int*p2)int p;p=*p1;*p1=*p2;*p2=p;a ab bpoint_1point_2&a&b48p1p284point_1point_2&a&bvoid swap(int*p1,int*p2)int *p;p=p1;p1=p2;p2=p;void main()int a,b;int*point_1,*point_2;scanf(%d%d,&a,&b);point_1=&a;point_2=&b;if(ab)swap(point_1,point_2);printf(n%d,%dn,a,b);printf(n%d,%dn,*point_1,*point_2);a b point_1point_2输入数据:输入数据:4 84 8p1p2 point_1point_2输出结果:输出结果:4,84,8注:注:1.1.不能企图通过改变形参地址而使实参地址也改变,不能企图通过改变形参地址而使实参地址也改变,也就是说调用函数也就是说调用函数不能改变不能改变实参指针变量的值。实参指针变量的值。2.2.调用函数调用函数可以改变可以改变实参指针变量实参指针变量所指变量的值所指变量的值。ap1bp2cp3例例2:输入:输入a,b,c 三个整数,按大小顺序输出。三个整数,按大小顺序输出。void swap(int*pt1,int*pt2)int*pt1,*pt2;int p;p=*pt1;*pt1=*pt2;*pt2=p;void exchange(q1,q2,q3)int*q1,*q2,*q3;if(*q1*q2)swap(q1,q2);if(*q1*q3)swap(q1,q3);if(*q2*q3)swap(q2,q3);void main()int a,b,c,*p1,*p2,*p3;scanf(%d%d%d,&a,&b,&c);p1=&a;p2=&b;p3=&c;exchange(p1,p2,p3);printf(n%d,%d,%dn,a,b,c);5103&b&a&cq1q2q3pt1pt210 5q1q2q3 10.3 10.3 数组的指针和指向数组的指针变量数组的指针和指向数组的指针变量数组的指针和指向数组的指针变量数组的指针和指向数组的指针变量一、指向数组元素的指针变量一、指向数组元素的指针变量 与前面介绍的指向变量的指针变量相同。与前面介绍的指向变量的指针变量相同。若:若:int a10,*p;p=&a0;则:则:(1)p+i和和a+i就是就是ai的地址,或者说它们指向数组的第的地址,或者说它们指向数组的第i个个 元素。元素。(2)*(p+i)或或*(a+i)是是p+i或或a+i所指向的数组元素,即所指向的数组元素,即ai。(3)指向数组的指针变量可以带下标,如指向数组的指针变量可以带下标,如pi与与*(p+i)等价。等价。数组的指针是指数组的起始地址,数组元素的指针数组的指针是指数组的起始地址,数组元素的指针是数组元素是数组元素 的地址。的地址。指针法:指针法:main()int *p,i,a10;p=&a0;for(i=0;i10;i+)scanf(%d,p+);printf(n);p=&a0;for(i=0;i10;i+)printf(%3d,*p+);pa0a1a2a9例例1:输出数组全部元素。:输出数组全部元素。(设设a数组,整型,数组,整型,10个元素个元素)3p5pp-4p12pp*(p+i);p+i);p=a;p=a;(2)下标法下标法main()int a10;int i;for(i=0;i10;i+)scanf(%d,&ai);printf(n);for(i=0;i10;i+)printf(%3d,ai);(3)地址法地址法main()int a10;int i;for(i=0;i10;i+)scanf(%d,a+i);printf(n);for(i=0;i10;i+)printf(%3d,*(a+i);在使用指针变量时应注意的几个问题:在使用指针变量时应注意的几个问题:1.数组名是数组的首地址,因此数组名是数组的首地址,因此 p=&a0 与与 p=a 等价等价。2指针变量可以实现使本身的值改变,数组名不可以。指针变量可以实现使本身的值改变,数组名不可以。例例:p+正确正确 a+不正确不正确 3要注意指针变量的当前值。要注意指针变量的当前值。4指针变量可以指到数组后的内存单元。指针变量可以指到数组后的内存单元。5注意指针变量的运算,若先使注意指针变量的运算,若先使p指向数组指向数组a(即即p=a),则,则 (1)p+(或或p+=1)指向下一个元素。指向下一个元素。(2)*p+等价于等价于*(p+)先得到先得到p指向的变量的值,指向的变量的值,p再再 加加1。(3)*(p+)与与*(+p)作用不同,前者先取作用不同,前者先取*p,后使,后使p加加 1;后者相反。;后者相反。(4)(*p)+表示表示p所指向的所指向的元素值加元素值加1。(5)若若p当前指向当前指向a数组第数组第i个元素,则:个元素,则:*(p-)相当于相当于ai-,先取,先取p值作值作*运算,再使运算,再使p自减;自减;*(+p)相当于相当于a+i,先使,先使p自加,再作自加,再作*运算;运算;*(-p)相当于相当于a-i,先使,先使p自减,再作自减,再作*运算。运算。二、数组名作函数参数二、数组名作函数参数 用数组名作参数,在调用函数时实际上是把数组的首地址用数组名作参数,在调用函数时实际上是把数组的首地址传给形参,这样实参与形参共同指向同一段内存。因而调用过传给形参,这样实参与形参共同指向同一段内存。因而调用过程中,如形参数组元素值发生变化也就使实参数组的元素发生程中,如形参数组元素值发生变化也就使实参数组的元素发生了变化,但这种变化并不是从形参传回实参的,而是由于形参了变化,但这种变化并不是从形参传回实参的,而是由于形参与实参共享同一段内存而造成的。与实参共享同一段内存而造成的。例例2:将数组:将数组a中中n个整数按相反顺序存放。个整数按相反顺序存放。245760 11973379 11067542imjvoid inv(int x,int n)int i,j,t,m=n/2;for(i=0;im;i+)j=n-1-i;t=xi;xi=xj;xj=t;void main()int i,a10=3,7,9,11,0,6,7,5,4,2;printf(The original array:n);for(i=0;i10;i+);printf(%3d,ai);printf(n);inv(a,10);printf(The array has been inverted:n);for(i=0;i10;i+)printf(%3d,ai);printf(n);void inv(int*x,int n)int t,*i,*j;j=x+n-1;for(i=x;ij;i+,j-)t=*i;*i=*j;*j=t;a0a1a2a3a937911067542a4a5a6a7a8a a 数组数组i,xp=x+mj若将形参改为指针,则若将形参改为指针,则inv函数可改为:函数可改为:27911067543ji24911067573ij 如果有一个实参数组,想在函数中改变此数组的元素的如果有一个实参数组,想在函数中改变此数组的元素的值,实参与形参的对应关系有以下几类情况:值,实参与形参的对应关系有以下几类情况:(1)形参和实参都用形参和实参都用数组名数组名 传递的是实参数组首地址,形参与实参传递的是实参数组首地址,形参与实参共用同一段内存共用同一段内存单元。单元。(2)实参用实参用数组名数组名,形参用,形参用指针变量指针变量 通过指针变量值的改变可以指向实参数组的任一元素。通过指针变量值的改变可以指向实参数组的任一元素。(3)实参和形参都用实参和形参都用指针变量指针变量 先使实参指针变量指向数组的首地址,然后将实参的值先使实参指针变量指向数组的首地址,然后将实参的值 传给形参,通过指针变量值的改变可以使其指向数组的每个传给形参,通过指针变量值的改变可以使其指向数组的每个元素。元素。(4)实参为实参为指针变量指针变量,形参为,形参为数组名数组名 设设p为指针变量,令为指针变量,令p=&a0,p为实参,对应的形参为实参,对应的形参x为为数组名,则函数调用时将数组名,则函数调用时将 p的值传给形参数组名的值传给形参数组名x,也就是使,也就是使其取得其取得 a数组的首地址,使数组的首地址,使 x数组和数组和 a数组共用同一段内存单数组共用同一段内存单元元.例例3:用选择法对:用选择法对10个整数排序。个整数排序。void sort(int x,int n)int i,j,k,t;for(i=0;in-1;i+)k=i;for(j=i+1;jxk)k=j;if(k!=i)t=xi;xi=xk;xk=t;void main()int*p,i,a10;p=a;for(i=0;i10;i+)scanf(%d,p+);p=a;sort(p,10);for(p=a,i=0;i10;i+)printf(%d,*p+);(1)实参用实参用指针变量指针变量,形参用,形参用数组名数组名(2)实参用实参用数组名数组名,形参用,形参用指针变量指针变量void sort(int*x,int n)int i,j,k,t;for(i=0;in-1;i+)k=i;for(j=i+1;j*(x+k)k=j;if(k!=i)t=*(x+i);*(x+i)=*(x+k);*(x+k)=t;void main()int i,a10;for(i=0;i10;i+)scanf(%d,&ai);sort(a,10);for(i=0;i10;i+)printf(%3d,ai);(3)实参用实参用指针变量指针变量,形参也用,形参也用指针变量指针变量void main()int*p,i,a10;p=a;for(i=0;i10;i+)scanf(%d,p+);p=a;sort(p,10);for(p=a,i=0;i10;i+)printf(%d,*p+);void sort(int*x,int n)int i,j,k,t;for(i=0;in-1;i+)k=i;for(j=i+1;j*(x+k)k=j;if(k!=i)t=*(x+i);*(x+i)=*(x+k);*(x+k)=t;例例4:从:从10个数中找出其中最大值和最小值。个数中找出其中最大值和最小值。int max,min;void main()int i,number10;void max_min_value();printf(enter 10 datan);for(i=0;i10;i+)scanf(%d,&numberi);max_min_value(number,10);printf(n max=%d,min=%d,max,min);方法方法1:外部变外部变量量void max_min_value(int array ,int n)int*p,*array_end;array_end=array+n;max=min=*array;for(p=array+1;pmax)max=*p;else if(*pmin)min=*p;number 2 32 -12 4 56 7 28 -67 39 41arrayarray_endp22maxmin32p-12pp 56ppp-67ppp*array void main()int i,number10;int amax,amin,*amax_p,*amin_p;void max_min_value();printf(enter 10 datan);for(i=0;i10;i+)scanf(%d,&numberi);amax=amin=number0;amax_p=&amax;amin_p=&amin;max_min_value(number,10,amax_p,amin_p);printf(max=%d,min=%dn,*amax_p,*amin_p);方方法法2:2:amaxaminamax_pamin_p12-23 5 78 27 6 9 36 3 41212 void max_min_value(int array,int n,int*a1,int*b1)int i;for(i=1;i*a1)*a1=arrayi;else if(arrayi*b1)*b1=arrayi;amaxaminamax_pamin_p12-23 5 78 27 6 9 36 3 41212max_min_value(number,10,amax_p,amin_p);array10na1b1三、指向多维数组的指针和指针变量三、指向多维数组的指针和指针变量int a34=6,9,0,16,8,-1,2,7,3,48,-5,12;(1)a+i=ai=*(a+i)a=a0=*(a+0)=*a=&a00aa+0a+1a+2a0a1a2(2)ai+j是是aij的地址的地址 *(a+i)+j也是也是aij的地址的地址(3)&ai或或a+i指向指向行行,*(a+i)或或ai指向指向列列(4)aij的的值值可以表示为:可以表示为:*(ai+j)*(*(a+i)+j)aij690168-127348-5121多维数组的地址多维数组的地址对于一维数组对于一维数组ai=*(a+i)=*(p+i)=pi#define FORMAT%d,%dnvoid main()static int a34=1,3,5,7,9,11,13,15,17,19,21,23;printf(FORMAT,a,*a);printf(FORMAT,a0,*(a+0);printf(FORMAT,&a0,&a00);printf(FORMAT,a1,a+1);printf(FORMAT,&a10,*(a+1)+0);printf(FORMAT,a2,*(a+2);printf(FORMAT,&a2,a+2);printf(FORMAT,a10,*(*(a+1)+0);运行结果:运行结果:158,158158,158158,158166,166166,166174,174174,1749,9 2多维数组的指针多维数组的指针可以用指针变量指向多维数组及其元素可以用指针变量指向多维数组及其元素(1)指向数组元素的指针变量。指向数组元素的指针变量。例例5:用指针变量输出数组元素的值。:用指针变量输出数组元素的值。void main()static int a23=2,3,6,7,8,5;int i,j,*p;p=&a00;/*p=a0;或或 p=*a;*/for(i=0;i2;i+)for(j=0;j3;j+,p+)printf(%3d,*p);printf(n);2 3 6 7 8 5aa0a1p23 2 3 6pp6p7p8p5p例例6:用指针变量输出数组元素:用指针变量输出数组元素aij的值。的值。void main()static int a23=2,3,6,7,8,5;int i,j,*p;p=a;scanf(%d%d,&i,&j);printf(%3d,*(p+i*3)+j);void main()static int a45=1,4,2,3,7,6,9,10,8,-1,-2,-6,-4,4,2,7,6,9,11,14;int i,j;for(i=0;i4;i+)for(j=0;j5;j+)printf(%4d,aij);printf(n);sort(a,4*5);printf(=n);for(i=0;i4;i+)for(j=0;j5;j+)printf(%4d,aij);printf(n);例例7:7:将一个二维数组将一个二维数组a45a45进行按行全排序进行按行全排序 void sort(int*p,int n)int i,j,t;for(i=0;in-1;i+)for(j=i+1;j=n-1;j+)if(*(p+i)*(p+j)t=*(p+i);*(p+i)=*(p+j);*(p+j)=t;a00a01a02a03a04a10a11a12a13a14 .a32a33a34.sort(a,4*5);p(2)指向由指向由m个整数组成的一维数组的指针变量。个整数组成的一维数组的指针变量。例例7:输出二维数组任一行任一列的元素的值。:输出二维数组任一行任一列的元素的值。void main()static int a34=1,3,5,7,9,11,13,15,17,19,21,23;int(*p)4,i,j;p=a;scanf(i=%d,j=%d,&i,&j);printf(a%d,%d=%dn,i,j,*(*(p+i)+j);说明说明:(1)int(*p)4 表示表示p指向指向一个包含一个包含4个元素的个元素的一维数组一维数组.(2)p+1使指针移动使指针移动2*4个字节个字节,*(p+1)使指针的指向由横使指针的指向由横 向转向纵向向转向纵向.(3)*(p+i)+j使指针移动使指针移动2*4*i+2*j.(3)多维数组的指针作函数参数。多维数组的指针作函数参数。例例9:9:求二维数组求二维数组a45a45每列最大值每列最大值 void colum_max(a,b)int(*a)5,*b;int i,j;for(j=0;j5;j+)for(i=1;i4;i+)if(*(b+j)*(*(a+i)+j)*(b+j)=*(*(a+i)+j);int a45,b5;colum_max(a,b);a+0a+1a+2a+3b 2 12 3 27 -4 3 7 33 2 5 1 6 12 3 15 4 8 10 9 14 2 12 3 27 -4.3 4123327515 void main()int a45,b5;int i,j;for(i=0;i4;i+)for(j=0;j5;j+)scanf(%d,&aij);bj=a0j;colum_max(a,b);for(i=0;i4;i+)for(j=0;j5;j+)printf(%4d,aij);printf(n);printf(=n);for(j=0;j5;j+)printf(%4d,bj);printf(n);打印原二维数组打印原二维数组打印每列最大值打印每列最大值