《樊媛媛《c语言程序设计》10-指针.ppt》由会员分享,可在线阅读,更多相关《樊媛媛《c语言程序设计》10-指针.ppt(68页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、第十章第十章 指针指针 指指针针:C C的的一一个个重重要要概概念念、重重要要特特色色。它它使使C C具具备备了了强强大大的的功功能能,使使C C成成为为程程序序设设计计语语言言之之首首。正正确确而而灵灵活活地地运运用用它它,就就可可以以方方便便地地处处理理很很多多其它高级语言所不能处理的问题。其它高级语言所不能处理的问题。不掌握不掌握指针指针等于没有掌握等于没有掌握C C语言的语言的精华精华。10 101 1 指针的概念指针的概念 简单地说,简单地说,指针就是地址指针就是地址。要掌握指针的概念就必须弄清:要掌握指针的概念就必须弄清:内存地址概念内存地址概念?变量与地址的关系变量与地址的关系?
2、如何通过地址进行变量的存取如何通过地址进行变量的存取?说明例:说明例:内存用户数据10003i10026j10049k对变量值的存取总是按地址进行的-直接访问。inti,j,k;i=3;j=6;k=i+j;程程序序经经编编译译后后,变变量量名名就就不不复复存存在在,以以地地址址对应。对应。也可以采用也可以采用“间接访问间接访问”方式:方式:先先将将变变量量i i的的地地址址存存放放到到另另一一变变量量p1p1中中,要要访访问问i i时时,先先取取出出p1p1的的内内容容(变变量量i i的的地地址址),再再去去访访问问该该地地址址所所对对应应的的内内存存单单元元中中的的内内容容(变量(变量i i
3、的值)。的值)。内存用户数据10003i10026j10049k20001000p120041002p2inti,j,k;i=3;j=6;k=i+j;int*p1,*p2;p1=&i;p2=&j;在以上概念的基础上对指针下定义:在以上概念的基础上对指针下定义:变量的地址就是该变量的变量的地址就是该变量的指针指针。存放地址的变量称存放地址的变量称指针变量指针变量。若若p1p1存放了变量存放了变量i i的地址,的地址,则称则称p1p1是是指向变量指向变量i i的指针变量的指针变量。10001002100410001002ijkp1p2369inti,j,k;i=3;j=6;k=i+j;int*p1
4、,*p2;p1=&i;p2=&j;10 102 2 变量的指针和指向变量的指针变量变量的指针和指向变量的指针变量 变量的指针变量的指针 指针变量指针变量 指向变量的指针变量指向变量的指针变量 用用“*”代表代表“指向指向”如如*p1*p1代表它所指向的变量代表它所指向的变量i i,同一内存单元。,同一内存单元。以下两个语句等价:以下两个语句等价:i=3;i=3;直接访问直接访问 *p1=3;*p1=3;间接访问间接访问int i,*p1;int i,*p1;p1=&i;p1=&i;内存用户数据10003i10026j10049k20021000p120041002p2inti,j,k;i=3;
5、j=6;k=i+j;int*p1,*p2;p1=&i;p2=&j;*p1=5;*p2=8;58 指针变量的定义指针变量的定义 指针变量也必须先定义后使用。指针变量也必须先定义后使用。int *p1;int *p1;注意:注意:*表示该变量为指针变量,但变量名是表示该变量为指针变量,但变量名是p1p1。一个指针变量只能指向同一类型的变量。一个指针变量只能指向同一类型的变量。int i,*p1;int i,*p1;float a;float a;p1=&i;p1=&i;合法合法 p1=&a;p1=&a;不合法不合法 指针变量的引用指针变量的引用 两种用法:两种用法:用地址运算符用地址运算符&p1=
6、&i p1=&i;用指针运算符用指针运算符*(实行间接访问)(实行间接访问)*p1=100;k=*p1;*p1=100;k=*p1;注意:注意:指针变量只能放地址(指针)。指针变量只能放地址(指针)。p1=100;p1=100;不允许不允许 使使用用指指针针运运算算符符*之之前前,p1p1必必须须被被赋赋值值(即即p1p1必必须存放了某个变量的地址)须存放了某个变量的地址)例:例:T10-1.c注意:要区别定义和引用中的“*”main()inta=100,b=10;int*p1,*p2;定义指针变量,尚无体定义指针变量,尚无体指向指向p1=&a;p1p1指向指向a ap2=&b;p2p2指向指
7、向b bprintf(“*p1=%d,*p2=%dn”,*p1,*p2);printf(“&a=%x,&b=%xn”,&a,&b);printf(“p1=%x,p2=%xn”,p1,p2);printf(“&p1=%x,&p2=%xn”,&p1,&p2);运算结果:*p1=100,*p2=10&a=12ff7c,&b=12ff78p1=12ff7c,p2=12ff78&p1=12ff74,&p2=12ff70要特别注意以下用法的后果:要特别注意以下用法的后果:egp1.cint*p1;*p1=100;例例:输输入入a a和和b b两两个个整整数数,按按先先大大后后小小的的顺顺序序输输出出mai
8、n()T10-2.cinta,b,*p1,*p2,*p;scanf(“%d,%d”,&a,&b);10005ap1=&a;p2=&b;10029bif(ab)p=p1;p1=p2;p2=p;printf(“n%d,%d”,a,b);2000p1printf(“n%d,%d”,*p1,*p2);2004p22006p 改变p1和p2的指向10001002100210001000重要概念:重要概念:只只要要将将某某一一变变量量的的地地址址存存入入指指针针变变量量中中,就可通过指针变量间接访问该变量。就可通过指针变量间接访问该变量。配钥匙!配钥匙!swap(intp1,intp2)intt;t=p1
9、;p1=p2;p2=t;10005a10029bmain()inta,b;scanf(“%d,%d”,&a,&b);2000p1if(ab)swap(a,b);2004p2printf(“n%d,%d”,a,b);2006tT10-3-1.c59 595例不用指针变量作函数参数,将两个整数按大小顺序输出。怎样直接修改a、b的值呢?修改原件修改原件用指针!用指针!指针变量作为函数的参数指针变量作为函数的参数 可将指针变量作函数的参数,接受实参可将指针变量作函数的参数,接受实参地址,获得具体指向,进而通过指针变量间地址,获得具体指向,进而通过指针变量间接访问主调函数的变量。接访问主调函数的变量。例
10、T10-3.c用指针变量作函数参数,将两个整数按大小顺序输出。swap(int*p1,int*p2)intt;t=*p1;*p1=*p2;*p2=t;10005a10029bmain()inta,b;scanf(“%d,%d”,&a,&b);2000p1if(ab)swap(&a,&b);2004p2printf(“n%d,%d”,a,b);2006t10001002595重重要要概概念念:使使用用指指针针变变量量作作函函数数参参数数,被调函数可以将多个结果交给主调函数。被调函数可以将多个结果交给主调函数。数组名做参数,可返回该数组所有元素数组名做参数,可返回该数组所有元素 还还记记得得那那个
11、个求求成成绩绩最最高高、最最低低和和平平均均值值的例子?还需要用全局变量吗?的例子?还需要用全局变量吗?例例T10-4-2.c T10-4-2.c:求:求n n个数的最大值、最小值和平均值。个数的最大值、最小值和平均值。floataver(inta,intn,int*max,int*min)inti;floats=0;*max=a0;*min=a0;for(i=0;i*max)*max=ai;if(ai*min)*min=ai;return(s/100);main()inta100,i,max,min;floatav;for(i=0;i100;i+)scanf(“%d”,&ai);av=ave
12、r(a,100,&max,&min);printf(“%d,%d,%f”,max,min,av);例例T10-4-1.c:编写函数,求一元二次方程的两个实根。:编写函数,求一元二次方程的两个实根。#include“math.h”?root(floata,floatb,floatc,)floatd;d=b*b-4*a*c;if(d0|a=0)return(0);?=(-b+sqrt(d)/2/a;?=(-b-sqrt(d)/2/a;return(1);float*x1,float*x2*x1*x2intmain()intk;floata,b,c,x1,x2;scanf(“%f,%f,%f”,&a
13、,&b,&c);k=root(a,b,c,&x1,&x2);if(k)printf(“n%f,%f”,x1,x2);输入:1,-10,25输出:5.000000,5.000000函数参数:函数参数:如不需改变(只读):一般参数如不需改变(只读):一般参数如需改变(读写):指数参数如需改变(读写):指数参数 10 103 3 数组的指针和指向数组的指针变量数组的指针和指向数组的指针变量数组有一个首地址:数组的指针数组的指针。每个数组元素也都有地址:数组元素的指针数组元素的指针。532168742000200220042006指向数组元素的指针变量指向数组元素的指针变量inta10,*p;p=a;
14、指向数组指向数组p=&a0;指向数组元素指向数组元素51247680392000200220042006p 通过通过指针引用数组元素指针引用数组元素inta10,*p;p=&a0;或者或者p=a;/p p指向指向a0a0*p=1;等效于等效于a0=1a0=1;即可通过即可通过p p来访问来访问a0a0也可以通过也可以通过p p来访问其它元素:来访问其它元素:*(p+1)=3;*(p+1)=3;等效于等效于a1=3;a1=3;其中其中p+1p+1指向指向a1a1注意:注意:p+1p+1不是地址加不是地址加1 1,而是加一个数据类型单位。,而是加一个数据类型单位。一般地一般地,当当p p指向指向a
15、0a0时时,即即p=&a0;或者或者p=a;p+i a+i a+i&ai&ai*(p+i)*(a+i)*(a+i)ai ai pi pi即以下几个语句等效:即以下几个语句等效:ai=10;*(p+i)=10;*(a+i)=10;pi=10;举例:用三种方法输出数组元素例T10-5-1.c用“数组名数组名+下标下标”的方法main()inti,a5;for(i=0;i5;i+)scanf(“%d”,&ai);for(i=0;i5;i+)printf(“&a%d=%x,a%d=%dn”,i,&ai,i,ai);输入:5566778899输出:&a0=ffce,a0=55&a1=ffd0,a1=66
16、&a2=ffd2,a2=77&a3=ffd4,a3=88&a4=ffd6,a4=99ffcc55a0ffce66a1ffd077a2ffd288a3ffd499a4ffd6a5举例:用三种方法输出数组元素例T10-5-2.c计算“数组名计算地址数组名计算地址”的方法main()inti,a5;for(i=0;i5;i+)scanf(“%d”,a+i);for(i=0;i5;i+)printf(“a+%d)=%x,*(a+%d)=%dn”,i,(a+i),i,*(a+i);输出:(a+0)=ffcc,*(a+0)=55(a+1)=ffce,*(a+1)=66(a+2)=ffd0,*(a+2)=7
17、7(a+3)=ffd2,*(a+3)=88(a+4)=ffd4,*(a+4)=99ffcc55a0ffce66a1ffd077a2ffd288a3ffd499a4ffd6a5举例:用三种方法输出数组元素例T10-5-3_new.c用“指针变量指针变量+下标下标”的方法(指针法指针法I)main()int*p,a5,i;p=a;for(i=0;i5;i+)scanf(“%d”,p+i);for(i=0;i5;i+)printf(&p%d=%x,p%d=%d,*(p+%d)=%dn,i,&pi,i,pi,i,*(p+i);12ff6c55p012ff7066p112ff7477p212ff7888
18、p312ff7c99p4输出:&p0=12ff6c,p0=55,*(p+0)=55&p1=12ff70,p1=66,*(p+1)=66&p2=12ff74,p2=77,*(p+2)=77&p3=12ff78,p3=88,*(p+3)=88&p4=12ff7c,p4=99,*(p+4)=99举例:用三种方法输出数组元素(例T10-5-4_new.c)用“指针变量指向数组元素指针变量指向数组元素”法(指针法指针法II)main()int*p,a5;for(p=a;p(a+5);p+)scanf(“%d”,p+i);for(p=a;p(a+5);p+)printf(“p=%x,*p=%dn”,p,*
19、p);输出:p=12ff6c,*p=55p=12ff70,*p=66p=12ff74,*p=77p=12ff78,*p=88p=12ff7c,*p=9912ff6c55a012ff7066a112ff7477a212ff7888a312ff7c99a4p+:合法,因p是指针变量,而变量可以用+运算符的a+:不合法,因为a是数组名,其值是数组元素的首地址,分配之后不可变。举例:用三种方法输出数组元素(例T10-5-4.c)指针变量当作数组名使用(混合指针法)main()inta5,*p=a,i;for(p=a;pa+5;p+)scanf(“%d”,p);p=a;/不能漏!不能漏!for(i=0;
20、i5;i+)printf(“&p%d=%x,p%d=%d,*(p+%d)=%dn”,i,&pi,i,pi,i,*(p+i);输出:&p0=12ff6c,p0=55,*(p+0)=55&p1=12ff70,p1=66,*(p+1)=66&p2=12ff74,p2=77,*(p+2)=77&p3=12ff78,p3=88,*(p+3)=88&p4=12ff7c,p4=99,*(p+4)=9912ff6c55p12ff7066p+112ff7477p+212ff7888p+312ff7c99p+4通过通过指针引用数组元素的方法小结指针引用数组元素的方法小结例:累加求和的各种用法:例:累加求和的各种用
21、法:int*p,a10;s=0;p=a;for(i=0;i10;i+)s+=ai;for(i=0;i10;i+)s+=*(a+i);for(i=0;i10;i+)s+=*(p+i);for(i=0;i10;i+)s+=pi;for(i=0;i10;i+)s+=*p+;for(p=a;pa+10;p+)s+=*p;最后一种用法效率高。数组元素地址法数组元素地址法指针法指针法I指针变量指向数组元素指针法II指针变量当作数组名注意不能注意不能使用a+指针变量使用时的几个问题,指针变量使用时的几个问题,若若p当前指向当前指向a数组的第数组的第i个元素,则:个元素,则:10-plus.c*p:是取出是取
22、出ai的值的值.p+:指针指向指针指向ai+1.*p+:等价于等价于*(p+)及及ai+,优先级同为优先级同为2,从右向左结合从右向左结合,将将ai的值取出的值取出,后再使后再使p增增1(不是单纯的加一,是不是单纯的加一,是p指向指向ai+1).*(+p):与与a+i等价,先将等价,先将p指向指向ai+1,然后将该元素取出然后将该元素取出.(*p)+:将将p所指的数组元素所指的数组元素ai的值取出的值取出,使使ai的值增的值增1.p-:指针指向指针指向ai-1.*(p-):与与ai-等价,等价,将将p所指向的第所指向的第i个数组元素取出个数组元素取出,然后然后使使p指向指向i-1元素元素.*(
23、-p):与与a-i等价,先将等价,先将p减减1指向第指向第i-1个元素个元素,然后将其取然后将其取出出.(*p)-:将将p所指的数组元素所指的数组元素ai的值取出的值取出,使使ai的值减的值减1.数组名作为函数参数数组名作为函数参数 有有了了指指针针概概念念的的基基础础上上,重重新新回回顾顾数数组组名名作作为函数参数时,数据的传递情况:为函数参数时,数据的传递情况:void sort(void sort(int aint a,int n),int n)void sort(void sort(int*aint*a,int n),int n)例:例:选择法排序函数选择法排序函数 voidsort(
24、int*a,intn)例T10-7-1.cinti,j,t;for(i=0;in-1;i+)for(j=i+1;jaj)t=ai;ai=aj;aj=t;只将形参改为指针变量,仍按下标法使用只将形参改为指针变量,仍按下标法使用voidsort(int*a,intn)inti,j,t;for(i=0;in-1;i+)for(j=i+1;j*(a+j)t=*(a+i);*(a+i)=*(a+j);*(a+j)=t;按指针法使用按指针法使用例T10-7-2.c进进一一步步优优化化:都都用用指指针针,效效率率更更高高!(例T10-7-3.c)voidsort(int*a,intn)int*i,*j,t;
25、for(i=a;ia+n-1;i+)for(j=i+1;j*j)t=*i;*i=*j;*j=t;main()inta10,j;for(j=0;j10;j+)scanf(“%d”,a+j);sort(a,10);for(j=0;j10;j+)printf(“%5d”,aj);分段排序?分段排序?例T10-7-4.cmain()inta10,j;for(j=0;j10;j+)scanf(“%d”,a+j);for(j=0;j10;j+)printf(“%5d”,aj);sort(a,5);sort(a+5,5);voidsort(int*a,intn)int*i,*j,t;for(i=a;ia+n
26、-1;i+)for(j=i+1;j*j)t=*i;*i=*j;*j=t;指向多维数组的指针和指针变量指向多维数组的指针和指针变量 从本质上说,多维数组的指针与一维数组从本质上说,多维数组的指针与一维数组的指针相同,但在概念上和使用上,多维数组的指针相同,但在概念上和使用上,多维数组的指针要复杂些。的指针要复杂些。以二维数组的指针为例:以二维数组的指针为例:二维数组的地址:一维:a,&ai,a+i 二维:aa+i(行指针:指向第i行)ai*(a+i)(特殊的一维数组,列指针,指向行中的列)ai+j *(a+i)+j&aij inta34135791113151719212310001008101
27、6a+0a+1a+2a0讨论以下用法的效果:讨论以下用法的效果:T10-8-1.cfor(i=0;i3;i+)scanf(“%d”,a+i);输入数据:输入数据:123讨论以下用法的效果:讨论以下用法的效果:T10-8-2.cfor(i=0;i3;i+)scanf(“%d”,a1+i);输入数据:输入数据:123讨论以下用法的效果:讨论以下用法的效果:T10-8-3.cfor(i=0;i3;i+)scanf(“%d”,a1+i+2);输入数据:输入数据:123讨论以下用法的效果:讨论以下用法的效果:T10-8-4.cfor(i=0;i3;i+)scanf(“%d”,a+i+1);输入数据:输入
28、数据:123a0+1 a0+2 a0+3一维数组与二维数组的比较一维数组与二维数组的比较第第i个个一维数组一维数组的第的第j个元个元素的地址素的地址无意义无意义*(a+i)+j第第i个个一维数组一维数组的第的第j个元个元素的值素的值无意义无意义*(*(a+i)+j)第第i个个一维数组一维数组的值的值第第i个个一维数组一维数组的首地址的首地址第第i个元素的值个元素的值*(a+i)第第i个个元素元素 的地址的地址一维数组一维数组第第i个元素的地址个元素的地址a+i二维数组的首地址二维数组的首地址一维数组的首地址一维数组的首地址a二维数组二维数组一维数组一维数组注意:注意:指针运算符指针运算符*作用
29、在行指针上的结果仍是指针作用在行指针上的结果仍是指针-列指针列指针;*作用在列指针上的结果作用在列指针上的结果-具体元素具体元素。*(a+0),*(a+1),*(a+2)仍是地址仍是地址。*(a+i)ai*(a0),*(a1),*(a1)具体元素值具体元素值。*(ai)*(a+i)+j也是地址,但要区别:也是地址,但要区别:(a+i)+j行指针行指针(a+1)+1?*(a+i)+j列指针列指针*(a+1)+1?100010081016a+0a+1a+2a0a1a2*(a+1)1357911131517192123如如果果要要通通过过a+ia+i形形式式的的地地址址访访问问数数组组元元素素的的具
30、具体体内容,则:内容,则:*(*(a+i)或或*(*(a+i)+j)如如:*(*(a+1)a10*(*(a+1)+2)a12讨论:讨论:例T10-8-5.c*(a+2)*(*(a+1)+3)*(a1+1)*(*(a+1)+5)123456789111012例:求数组例:求数组a a的所有元素之和。的所有元素之和。可有多种用法:可有多种用法:例T10-9-1.cT10-9-3.c M M行行N N列列for(i=0;iM;i+)for(i=0;iM;i+)for(i=0;iM;i+)for(i=0;iM;i+)for(j=0;jN;j+)for(j=0;jN;j+)for(j=0;jN;j+)f
31、or(j=0;jN;j+)s+=s+=aijaij;s+=;s+=*(ai+j)*(ai+j);for(i=0;iM;i+)for(i=0;iM;i+)for(j=0;jN;j+)for(j=0;jN;j+)s+=s+=*(*(a+i)+j)*(*(a+i)+j);aij*(ai+j)*(*(a+i)+j)指向二维数组的指针变量指向二维数组的指针变量 同样可使一个指针变量同样可使一个指针变量p p指向二维数组指向二维数组a a,再通,再通过过p p访问数组元素。访问数组元素。例T10-10.cmain()main()int a34=1,2,3,4,5,6,7,8,9,10,11,12;int
32、a34=1,2,3,4,5,6,7,8,9,10,11,12;int i,k,*p;int i,k,*p;p=a;p=a;k=*p;k=*p;?k=*(p+2);k=*(p+2);?for(p=a;pa+2;p+)printf(“%3d,”,*p);for(p=a;pa+2;p+)printf(“%3d,”,*p);?N列:列:aij*(p+i*N+j)pi*N+j123456789101112k=p12;不合法不合法k=*(*(p+1)+2);k=p1*4+2;合法合法k=*(p+1*4+2);例:求矩阵的上三角元素之和。例:求矩阵的上三角元素之和。例T10-11.cmain()inta34
33、,*p,i,j,s=0;输入输入ap=a;for(i=0;i3;i+)for(j=i;j4;j+)s+=pi*4+j;或或s+=*(p+4*i+j)printf(“n%d”,s);/s=54N列:列:aij*(p+i*N+j)pi*N+j123456789101112 多维数组的指针作函数参数维数组的指针作函数参数 用于接受实参数组地址的形参可用两种:用于接受实参数组地址的形参可用两种:行指针行指针和和列指列指针针。以方阵转置为例:以方阵转置为例:例T10-13-1.c void at(int void at(int (*p)3(*p)3)用行指针用行指针 int i,j,t;int i,j,
34、t;缺点:不通用(必须制定列数)缺点:不通用(必须制定列数)for(i=0;i3;i+)for(i=0;i3;i+)for(j=i+1;j3;j+)for(j=i+1;j3;j+)t=pij;pij=pji;t=pij;pij=pji;pji=t;pji=t;p p指向一个包含指向一个包含3 3个整形元素的一维数组(行指针),个整形元素的一维数组(行指针),p p相相当于一个二维数组!当于一个二维数组!用列指针:用列指针:例T10-13-2.c void at(int void at(int *p*p,int ,int n n)/n)/n为列数为列数 int i,j,t;int i,j,t;f
35、or(i=0;i for(i=0;in n;i+);i+)for(j=i+1;j for(j=i+1;jn n;j+);j+)t=t=pi*n+jpi*n+j;pi*n+jpi*n+j=pj*n+ipj*n+i;pj*n+ipj*n+i=t;=t;优点:通用 在编通用函数时,一般使用列指针。用列指针:用列指针:例T10-13-3.c int sum(int int sum(int*p*p,int,int m m,int,int n n)/m)/m行行n n列列 int i,j,s=0;int i,j,s=0;for(i=0;im;i+)for(j=i;jn;j+)s+=pi*n+j;或或s+=
36、*(p+n*i+j)return(s);优点:通用 在编通用函数时,一般使用列指针。10104 4 字符串的指针和指向字符串的指针变量字符串的指针和指向字符串的指针变量 字符串的表示形式字符串的表示形式 可用两种方法访问字符串:可用两种方法访问字符串:用字符数组存放字符串用字符数组存放字符串 用字符指针指向一个字符串用字符指针指向一个字符串例T10-14.cmain()main()char char str5=”abc”;str5=”abc”;定定义义字字符符数数组组,并并将将字字符符串串存入存入 char *p=str;char *p=str;定义指针变量,指向字符串定义指针变量,指向字符串
37、 printf(“%s”,str);printf(“%s”,str);通过数组名访问字符串通过数组名访问字符串 printf(“%s”,p);printf(“%s”,p);通过指针变量访问字符串通过指针变量访问字符串 printf(“%c”,*(p+2);printf(“%c”,*(p+2);通过指针变量访问字符通过指针变量访问字符 strab c 0abc010001000p 与与其其它它一一维维数数组组的的指指针针相相比比,字字符符串串的的指指针针有其有其独特之处独特之处:可以通过指针对字符串进行整体访问。可以通过指针对字符串进行整体访问。对字符串的操作依赖于对字符串的操作依赖于结束符结束
38、符。可以可以整体赋初值整体赋初值。有各种字符串处理函数。有各种字符串处理函数。本节重点掌握:本节重点掌握:通通过过数数组组和和通通过过指指针针操操作作字字符符串串的的基本方法。基本方法。常用的字符串处理方法。常用的字符串处理方法。例:字符串拷贝操作。例:字符串拷贝操作。例T10-15-1.c,例T10-15-2.cmain()chara=”abcdef”,b20;inti;for(i=0;*(a+i)!=0;i+)*(b+i)=*(a+i);*(b+i)=0;printf(“%s”,b);main()chara=”abcdef”,b20,*p1,*p2;p1=a;p2=b;for(;*p1!=
39、0;p1+,p2+)*p2=*p1;*p2=0;printf(“%s”,b);用指针变量处理将拷贝操作编成一函数:将拷贝操作编成一函数:例T10-15-3.c,例T10-15-4.cvoidcopy_string(char*from,char*to)for(;*from;from+,to+)*to=*from;*to=0;还可以改成:还可以改成:voidcopy_string(char*from,char*to)for(;*from;)*to+=*from+;*to=0;字符串合并函数:字符串合并函数:例T10-16.c,void append_string(char *from,char *
40、to)void append_string(char *from,char *to)for(;*to;to+);for(;*to;to+);for(;*from;)*to+=*from+;for(;*from;)*to+=*from+;*to=0;*to=0;阅读程序:阅读程序:例T10-17.cvoidf(char*c)main()c+=2;charc20=”abcdef”;(*c)+;f(c+1);c+;*c=0;printf(“%s”,c);内存空间的动态分配内存空间的动态分配 在在程程序序设设计计中中,对对于于要要处处理理的的批批量量数数据据,我我们们往往往往是是选选用用数数组组作作为
41、为存存放放这这些些数数据据的的数数据据结结构构,然然而而,数数组组有有一一个个明明显显的的缺缺点点,就就是是在在定定义义数数组组时时,其其长长度度必必须须是是常常值值,无无法法根根据据需需要要动动态态地地定定义义。这这样样,在在很很多多情情况况下下,不不是是定定义的数组长度不够,就是定义太长以至于浪费。义的数组长度不够,就是定义太长以至于浪费。采用动态分配可以克服这一缺点,并且可采用动态分配可以克服这一缺点,并且可以随时释放。以随时释放。动态分配内存空间步骤:动态分配内存空间步骤:定义一指针变量。定义一指针变量。申申请请一一片片内内存存空空间间,并并将将其其首首地地址址赋赋给给指指针针变变量量
42、。此此时时便便可可通通过过指指针针变变量量访访问问这这片片内内存存;不不成成功功则则返返回回地地址址为为0 0 用完后释放这片内存空间。用完后释放这片内存空间。int *p;int *p;p=p=mallocmalloc(字节数字节数););freefree(p);(p);sizeofsizeof(类型类型):):返回该类型数据在当前编译系统中所占的返回该类型数据在当前编译系统中所占的字节数。字节数。以上函数的原形在以上函数的原形在stdio.hstdio.h中中。p例:对例:对n n个学生的分数排序后输出。个学生的分数排序后输出。例T10-18.c#include “stdio.h”#inc
43、lude “stdio.h”void sort(int *a,int n)void sort(int *a,int n)main()main()int *a,j,n;int *a,j,n;scanf(“%d”,&n);scanf(“%d”,&n);a=a=mallocmalloc(n*(n*sizeofsizeof(int);(int);if(!a)exit(0);if(!a)exit(0);for(j=0;jn;j+)scanf(“%d”,a+j);for(j=0;jn;j+)scanf(“%d”,a+j);sort(a,n);sort(a,n);for(j=0;jn;j+)printf(“
44、%5d”,aj);for(j=0;jy)z=x;elsez=y;return(z);main()int(*p)();定义指向函数的指针变量定义指向函数的指针变量p pinta,b,c;p=max;将将p p指向函数指向函数maxmaxscanf(“%d%d”,&a,&b);c=(*p)(a,b);通过通过p p调用函数调用函数maxmax 等效于等效于c=max(a,b);c=max(a,b);printf(“n%d”,c);例T10-19.c把指向函数的指针变量作为函数参数把指向函数的指针变量作为函数参数 指向函数的指针变量最常见的用途是把它指向函数的指针变量最常见的用途是把它作为函数的参数
45、,用于接受主调函数传来的某作为函数的参数,用于接受主调函数传来的某一函数的入口地址,从而在被调函数中可以通一函数的入口地址,从而在被调函数中可以通过该指针变量调用它所指向的函数,这样,被过该指针变量调用它所指向的函数,这样,被调函数中就可实现非固定函数的调用,以达到调函数中就可实现非固定函数的调用,以达到编写通用函数的目的。编写通用函数的目的。例:用矩形法编写一个通用的求定积分的函数。例:用矩形法编写一个通用的求定积分的函数。关键问题:如何处理被积函数是未知的。关键问题:如何处理被积函数是未知的。double intgral(double a,double b,int n,double int
46、gral(double a,double b,int n,double (*f)()double (*f)()int i;int i;double h,x,y,s=0;double h,x,y,s=0;h=(b-a)/n;h=(b-a)/n;for(i=1;i=n;i+)for(i=1;i=n;i+)x=a+(i-1)*h;x=a+(i-1)*h;y=y=(*f)(x)(*f)(x);s+=h*y;s+=h*y;return(s);return(s);例T10-20.cdoublef1(doublex)return(3*x*x+2*x-1);main()doubles;s=intgral(1.
47、0,2.0,100,f1);10.8指针型数据小结一、有关指针的数据类型一、有关指针的数据类型(见下表)p是一个指针变量,它指向一个指向整型数据的指针变量int*pp为指向函数的指针,该函数返回一个整型值int(*p)()int(*p)()p为一个函数,它返回一个指针,该指针指向一个整型数据int*p()int*p()f为返回整型数据的函数int f()定义指针变量p,它指向一个含n个整型元素的一维数组int(*p)n定义指针数组p,它由n个指向整型数据的指针元素组成int*pnint*pn定义整型数组a,它有n个元素int an定义指向整型数据的指针变量pint*p定义整型变量iint i含
48、义定义二、指针运算小结二、指针运算小结1、指针变量加减一个整数、指针变量加减一个整数如:p+p-p+ip-ip+=ip-=i等实际含义如p+i代表地址计算:p+c*i,c为字节数,例如字符型c=1。2、指针变量赋值、指针变量赋值如:p=&aa为变量,p为指针变量p=arrayarray为数组名p=&arrayip=maxmax为函数名p1=p2p2为指针变量注意:不能把一个整数或常数赋给p,如p=1000同样也不能把p赋给整型变量,如i=p3、指针变量可以赋空值、指针变量可以赋空值如:p=NULL;实际NULL是整数0。4、两个指针变量可以相减、两个指针变量可以相减如两个指针变量指向同一个数组
49、的元素(如右图),则p2-p1=4-1=3但p1+p2无意义。5、两个指针变量比较、两个指针变量比较若两个指针指向同一个数组的元素,则可以比较,如:p1p2inv(intx,intn)inti,j,m,t;main()m=(n-1)/2;for(i=0;i=m;i+)inta10,i;输入输入aj=n-1-i;inv(a,10);t=xi;输出输出axi=xj;xj=t;ax例例T10-6-1.c:将数组:将数组a中的中的n个数按相反顺序存放。个数按相反顺序存放。a与x共用同一片内存单元inv(int*x,intn)指针变量作函数参数时的传递情况inti,j,m,t;main()m=(n-1)/2;for(i=0;i=m;i+)inta10,i;j=n-1-i;输入输入at=xi;inv(a,10);xi=xj;输出输出axj=t;下标法例T10-6-2.c a10001000 xj=n-1-i;t=*(x+i);*(x+i)=*(x+j);*(x+j)=t;指针法指针法例T10-6-3.c进一步优化:进一步优化:例T10-6-4.cintinv(int*x,intn)main()int*i=x,*j=x+n-1,t;for(;ij;i+,j-)inta10,i;输入输入at=*i;inv(a,10);*i=*j;输出输出a*j=t;优点:优点:简练简练 效率高效率高ij