指针及其应用

上传人:痛*** 文档编号:181301957 上传时间:2023-01-12 格式:PPT 页数:74 大小:323.51KB
返回 下载 相关 举报
指针及其应用_第1页
第1页 / 共74页
指针及其应用_第2页
第2页 / 共74页
指针及其应用_第3页
第3页 / 共74页
点击查看更多>>
资源描述
第第8 8章章 指针及其应用指针及其应用第第8章指针及其应用章指针及其应用l学习目标学习目标l掌握指针的概念及基本操作,指针在数组和函数中的应用。掌握指针的概念及基本操作,指针在数组和函数中的应用。l学习内容学习内容l指针、指针变量的概念,指针变量定义及使用,指针与一维数组,指针、指针变量的概念,指针变量定义及使用,指针与一维数组,指针与二维数组,指针与字符串,指针与函数。指针与二维数组,指针与字符串,指针与函数。下一页下一页返返 回回第第8章章 指针及其应用指针及其应用8.1 指针的基本用法指针的基本用法8.2 指针与数组指针与数组8.3 指针与函数指针与函数 8.4 指针应用实例指针应用实例8.5 本章小结本章小结8.6 实训实训上一页上一页返返 回回8.1 指针的基本用法指针的基本用法8.1.1 指针的概念指针的概念计算机的内存是以字节为单位的一片连续的存储空间,每个字节都有计算机的内存是以字节为单位的一片连续的存储空间,每个字节都有一个编号,这个编号称为内存单元地址。这就如同旅馆的每个房间都一个编号,这个编号称为内存单元地址。这就如同旅馆的每个房间都有一个房间号一样,如果没有房间号,旅馆的工作人员就无法进行管有一个房间号一样,如果没有房间号,旅馆的工作人员就无法进行管理,同样没有字节编号,系统就无法对内存单元进行管理。理,同样没有字节编号,系统就无法对内存单元进行管理。若在程序中定义了一个变量,系统就会根据变量的类型为变量在内存若在程序中定义了一个变量,系统就会根据变量的类型为变量在内存中分配若干字节的存储空间,此后这个变量的单元地址也就确定了。中分配若干字节的存储空间,此后这个变量的单元地址也就确定了。有了变量的地址,就可以立即找到该变量所在的存储单元并进行数据有了变量的地址,就可以立即找到该变量所在的存储单元并进行数据的存取操作。这种通过变量地址存取变量值的方式称为变量的直接访的存取操作。这种通过变量地址存取变量值的方式称为变量的直接访问。问。程序中通常是通过变量名对变量进行访问,因为变量名是变量的符号程序中通常是通过变量名对变量进行访问,因为变量名是变量的符号地址,它与单元物理地址之间的联系由系统自动建立。地址,它与单元物理地址之间的联系由系统自动建立。提示:注意区分变量的地址和变量的值这两个概念。提示:注意区分变量的地址和变量的值这两个概念。下一页下一页返返 回回8.1 指针的基本用法指针的基本用法存储单元地址惟一地对应着(或指向)存储单元,因此存储单元地址惟一地对应着(或指向)存储单元,因此C语言将存储语言将存储单元地址形象地称为单元地址形象地称为指针指针。前面学习的变量,都是用来存放基本类型数据的,如存放整数或实数前面学习的变量,都是用来存放基本类型数据的,如存放整数或实数等,这些变量称为简单变量。在等,这些变量称为简单变量。在C语言中,还可以定义一种特殊的变语言中,还可以定义一种特殊的变量,这种变量专门用来存放另一个变量的地址(即指针),称为指针量,这种变量专门用来存放另一个变量的地址(即指针),称为指针变量。变量。如果如果p是指针变量,而且是指针变量,而且p中存放着变量中存放着变量a的地址,则称的地址,则称p指向指向a,常用,常用图图8-1所示的形式表示。那么可以通过指针变量所示的形式表示。那么可以通过指针变量p引用它所指向的变量引用它所指向的变量a,这种变量访问方式称为变量的间接访问。,这种变量访问方式称为变量的间接访问。本章主要介绍的内容就是变量的间接访问。本章主要介绍的内容就是变量的间接访问。下一页下一页返返 回回上一页上一页8.1 指针的基本用法指针的基本用法8.1.2 指针变量的定义和使用指针变量的定义和使用1.指针变量的定义指针变量的定义任何变量在使用前都必须定义,指针变量也一样。指针变量的一般定任何变量在使用前都必须定义,指针变量也一样。指针变量的一般定义形式为:义形式为:基类型名基类型名 *指针变量名;指针变量名;例如:例如:int *p1,*p2;说明:说明:(1)定义了两个指针变量,变量名为)定义了两个指针变量,变量名为p1和和p2,这两个变量只能用来,这两个变量只能用来存放地址。存放地址。(2)*是一个说明符用来说明定义的是指针变量,定义指针变量时必是一个说明符用来说明定义的是指针变量,定义指针变量时必须有。须有。(3)基类型表示指针变量所指向的变量的类型,也就是说,)基类型表示指针变量所指向的变量的类型,也就是说,p1、p2中只能存放整型变量的地址。中只能存放整型变量的地址。下一页下一页返返 回回上一页上一页8.1 指针的基本用法指针的基本用法2.指针变量的使用指针变量的使用(1)运算符)运算符“&”和和“*”运算符运算符“&”为取地址运算符,后跟一个变量,表示取变量的地址。为取地址运算符,后跟一个变量,表示取变量的地址。比如,比如,&a表示变量表示变量a的地址。的地址。运算符运算符“*”为间接访问运算符,后跟一个指针变量,表示取这个指针为间接访问运算符,后跟一个指针变量,表示取这个指针变量所指向的变量的值。变量所指向的变量的值。(2)指针变量的赋值)指针变量的赋值通过给指针变量赋地址值,可以让指针变量指向某个变量。例如有以通过给指针变量赋地址值,可以让指针变量指向某个变量。例如有以下定义和语句:下定义和语句:int a,b,*pa,*pb;pa=&a;/*指针变量指针变量pa指向变量指向变量a*/pb=&b;/*指针变量指针变量pb指向变量指向变量b*/下一页下一页返返 回回上一页上一页8.1 指针的基本用法指针的基本用法下面的定义和语句是错误的:下面的定义和语句是错误的:float x;int *p;p=&x;错误原因是错误原因是x的类型和的类型和p的基类型不一致。的基类型不一致。(3)通过指针变量引用变量)通过指针变量引用变量例如,有以下定义和语句:例如,有以下定义和语句:int i,j,*p;p=&i;*p=10;/*将将10赋给赋给p所指向的变量即变量所指向的变量即变量i,等价于赋值语句,等价于赋值语句i=10;*/下一页下一页返返 回回上一页上一页8.1 指针的基本用法指针的基本用法j=*p+1;/*取指针变量取指针变量p所指向的存储单元中的值加所指向的存储单元中的值加1后赋给变量后赋给变量j,j的的值为值为11*/*p=*p+1;/*取指针变量取指针变量p所指向的存储单元中的值,加所指向的存储单元中的值,加1后再放入后再放入p所所指向的存储单元中,也就是使变量指向的存储单元中,也就是使变量i的值增的值增1变为变为11*/小测验小测验int a=11,b=22,*pa,*pb;pa=&a;pb=&b;在上面程序段的基础上,执行语句在上面程序段的基础上,执行语句pa=pb;和执行语句和执行语句*pa=*pb;有什么不同?有什么不同?下一页下一页返返 回回上一页上一页8.1 指针的基本用法指针的基本用法【例【例8-1】通过指针变量访问整型变量。】通过指针变量访问整型变量。【程序代码】【程序代码】#include void main()int i,j,*pi;/*定义整型变量定义整型变量i和和j,指针变量,指针变量pi*/i=10;pi=&i;/*使指针变量使指针变量p指向变量指向变量i*/j=*pi+5;/*通过指针变量访问变量通过指针变量访问变量i,等价于等价于j=i+5;*/printf(%dn,i);printf(%d,%dn,*pi,j);下一页下一页返返 回回上一页上一页8.1 指针的基本用法指针的基本用法程序运行结果:程序运行结果:【例【例8-2】从键盘上输入任意三个实数,利用指针的方法将这三个实】从键盘上输入任意三个实数,利用指针的方法将这三个实数按大小进行排序。数按大小进行排序。【编程思路】【编程思路】(1)输入)输入3个实数分别放到变量个实数分别放到变量a、b、c中。中。(2)3个指针变量个指针变量p1、p2、p3分别指向变量分别指向变量a、b、c。(3)比较变量的值,最终使)比较变量的值,最终使p1指向最大值,指向最大值,p3指向最小值。指向最小值。(4)按顺序输出)按顺序输出p1、p2、p3所指向的变量的值。所指向的变量的值。下一页下一页返返 回回上一页上一页8.1 指针的基本用法指针的基本用法【程序代码】【程序代码】#include void main()float a,b,c,*p1,*p2,*p3,*p;printf(请输入请输入3个实数:个实数:);scanf(%f,%f,%f,&a,&b,&c);p1=&a;p2=&b;p3=&c;if(ab)p=p1;p1=p2;p2=p;if(ac)下一页下一页返返 回回上一页上一页上一页上一页8.1 指针的基本用法指针的基本用法p=p1;p1=p3;p3=p;if(bc)p=p2;p2=p3;p3=p;printf(%.2f,%.2f,%.2fn,*p1,*p2,*p3);程序运行结果:程序运行结果:该程序执行过程中,变量该程序执行过程中,变量a、b、c的值始终未变,只是使指针的值始终未变,只是使指针p1最终最终指向值最大的变量,使指针指向值最大的变量,使指针p3最终指向值最小的变量。最终指向值最小的变量。返返 回回8.2 指针与数组指针与数组8.2.1 指针与一维数组指针与一维数组1.指针的移动指针的移动当指针变量指向一串连续的存储单元(即数组)时,可以对指针变量当指针变量指向一串连续的存储单元(即数组)时,可以对指针变量加上或减去一个整数来进行指针的移动和定位。例如有如下语句:加上或减去一个整数来进行指针的移动和定位。例如有如下语句:int a5=10,20,30,40,50,*p,*q;p=&a0;指针指针p的指向情况如的指向情况如图图8-2(a)所示。在此基础上,随着下面各个语句的所示。在此基础上,随着下面各个语句的执行,指针执行,指针p和和q的指向会发生相应变化。的指向会发生相应变化。q=p+1;如图如图8-2(a)所示,使指针变量所示,使指针变量q指向数组元素指向数组元素a1q+;指针后移,指针变量指针后移,指针变量q指向数组元素指向数组元素a2q+=2;指针变量指针变量q指向数组元素指向数组元素a4下一页下一页返返 回回8.2 指针与数组指针与数组q-;指针变量指针变量q指向数组元素指向数组元素a3p+;指针变量指针变量p和和q的指向如的指向如图图8-2(b)所示所示 现在如果有语句现在如果有语句 i=*p;j=*q;则则i中的值为中的值为20,j中的值为中的值为40。若有语句。若有语句 k=q-p;则则k中的值为中的值为2。表达式。表达式pq的值为真,因为当前指针变量的值为真,因为当前指针变量p中中存的地址值小于指针变量存的地址值小于指针变量q中存的地址值。中存的地址值。2.数组元素的地址数组元素的地址C程序中,数组名是数组的首地址,即第程序中,数组名是数组的首地址,即第1个数组元素的地址,该地个数组元素的地址,该地址是地址常量,因此不能被修改或重新赋值,例如,对数组名址是地址常量,因此不能被修改或重新赋值,例如,对数组名a来说,来说,a+;或或a=&a2;都是错误的使用方法。都是错误的使用方法。虽然不能对数组名进行赋值,但可以通过数组名来表示数组元素的地虽然不能对数组名进行赋值,但可以通过数组名来表示数组元素的地址,从而也能达到引用数组元素的目的。址,从而也能达到引用数组元素的目的。例如:例如:int a10,*p;p=a;此时指针此时指针p指向数组指向数组a的第的第1个元素,如个元素,如图图8-3所示。数组元素地址的几种表示形式见所示。数组元素地址的几种表示形式见表表8-1。下一页下一页返返 回回上一页上一页8.2 指针与数组指针与数组3.数组元素的引用数组元素的引用针对数组元素地址的不同表示形式,数组元素的引用形式也有多种,针对数组元素地址的不同表示形式,数组元素的引用形式也有多种,见见表表8-2。下面语句通过数组名逐个输出数组下面语句通过数组名逐个输出数组a中各元素的值:中各元素的值:for(i=0;i10;i+)printf(%5d,*(a+i);这里首地址这里首地址a始终指向数组元素始终指向数组元素a0,并没有移动,通过变量,并没有移动,通过变量i值的变值的变化来引用到每个元素。化来引用到每个元素。下面语句通过移动指针来逐个输出数组下面语句通过移动指针来逐个输出数组a中各元素的值:中各元素的值:for(p=a;pa+10;p+)printf(%5d,*p);下一页下一页返返 回回上一页上一页8.2 指针与数组指针与数组此语句在执行过程中,指针此语句在执行过程中,指针p首先指向元素首先指向元素a0,输出操作输出的是第输出操作输出的是第一个元素的值,执行了一个元素的值,执行了p+后,指针指向了元素后,指针指向了元素a1,此时再做输出,此时再做输出操作,输出的是第二个元素的值,依次下去,指针会逐个指向每个元操作,输出的是第二个元素的值,依次下去,指针会逐个指向每个元素,再输出它们的值。当指针素,再输出它们的值。当指针p指向最后一个元素后面的存储单元时,指向最后一个元素后面的存储单元时,循环结束。循环结束。【例【例8-3】有一个数组】有一个数组score,存放存放10个学生的成绩,求平均成绩,要求个学生的成绩,求平均成绩,要求通过指针变量来访问数组元素。通过指针变量来访问数组元素。【程序代码】【程序代码】#include void main()下一页下一页返返 回回上一页上一页8.2 指针与数组指针与数组float score10,*p,sum=0,ave;printf(请输入请输入10个学生成绩:个学生成绩:);for(p=score;pscore+10;p+)scanf(%f,p);for(p=score;pscore+10;p+)sum+=*p;/*取各成绩累加到取各成绩累加到sum 中中*/ave=sum/10;/*求平均成绩求平均成绩*/printf(平均成绩平均成绩%.2fn,ave);程序运行结果:程序运行结果:下一页下一页返返 回回上一页上一页8.2 指针与数组指针与数组【例【例8-4】使数组中的元素逆序存放(不借助其它数组),要求用指】使数组中的元素逆序存放(不借助其它数组),要求用指针的方法处理。针的方法处理。【编程思路】【编程思路】(1)定义两个指针变量)定义两个指针变量p1、p2,使,使p1指向第一个元素、指向第一个元素、p2指向最后指向最后一个元素。一个元素。(2)将)将p1、p2所指向的数组元素的值互换,然后使所指向的数组元素的值互换,然后使p1指向第二个元指向第二个元素、素、p2指向倒数第二个元素,再做上面的互换操作,这样重复下去,指向倒数第二个元素,再做上面的互换操作,这样重复下去,直到直到p1指向了指向了p2的后面或的后面或p1和和p2指向了同一元素为止。指向了同一元素为止。【程序代码】【程序代码】#include void main()下一页下一页返返 回回上一页上一页8.2 指针与数组指针与数组 int a10,*p1,*p2,temp;printf(请输入请输入10个数:个数:);for(p1=a;p1a+10;p1+)/*输入一个整数,存放在输入一个整数,存放在p1所指的存所指的存储单元中储单元中*/scanf(%d,p1);for(p1=a,p2=a+9;p1p2;p1+,p2-)/*通过交换首尾对应位置上通过交换首尾对应位置上的值实现逆置的值实现逆置*/temp=*p1;*p1=*p2;*p2=temp;/*两个指针变量所指向两个指针变量所指向的元素的值互换的元素的值互换*/printf(逆序后数组的值:逆序后数组的值:);for(p1=a;p1a+10;p1+)下一页下一页返返 回回上一页上一页8.2 指针与数组指针与数组printf(%5d,*p1);printf(n);程序运行结果为:程序运行结果为:下一页下一页返返 回回上一页上一页8.2 指针与数组指针与数组8.2.2 指针与二维数组指针与二维数组1.二维数组元素的地址二维数组元素的地址例如:例如:int a33;与一维数组名一样,二维数组名与一维数组名一样,二维数组名a也是数组的首地址。但是二者不同也是数组的首地址。但是二者不同的是,二维数组名的基类型不是数组元素类型,而是一维数组类型,的是,二维数组名的基类型不是数组元素类型,而是一维数组类型,因此二维数组名因此二维数组名a是一个行指针,其指向如是一个行指针,其指向如图图8-4所示。所示。二维数组二维数组a包含三个行元素:包含三个行元素:a0、a1和和a2,而它们又都是一维数,而它们又都是一维数组名,因此也是地址常量,但是它们的基类型与数组元素类型一致。组名,因此也是地址常量,但是它们的基类型与数组元素类型一致。第第0行首地址:行首地址:a0第第1行首地址:行首地址:a1第第2行首地址:行首地址:a2下一页下一页返返 回回上一页上一页8.2 指针与数组指针与数组所以所以a0+1就是数组元素就是数组元素a01的地址,的地址,a1+1是数组元素是数组元素a11的地的地址,那么任意的数组元素址,那么任意的数组元素aij的地址是的地址是ai+j。二维数组元素的地址表示形式较多,每种地址形式都有对应的数组元二维数组元素的地址表示形式较多,每种地址形式都有对应的数组元素引用方法。比如:素引用方法。比如:数组元素地址:数组元素地址:&aij ai+j *(a+i)+j数组元素引用:数组元素引用:aij *(ai+j)*(*(a+i)+j)2.指向二维数组元素的指针变量(列指针)指向二维数组元素的指针变量(列指针)例如:例如:int a32,*p;p=&a00;二维数组在内存中是按行顺序存储的,因此,可以通过对指向数组元二维数组在内存中是按行顺序存储的,因此,可以通过对指向数组元素的指针变量进行加减运算来达到引用任意数组元素的目的,引用方素的指针变量进行加减运算来达到引用任意数组元素的目的,引用方法与引用一维数组元素一样。法与引用一维数组元素一样。下一页下一页返返 回回上一页上一页8.2 指针与数组指针与数组【例【例8-5】用指向数组元素的指针访问数组。】用指向数组元素的指针访问数组。【程序代码】【程序代码】#include void main()int a33=1,2,3,4,5,6,7,8,9;int *p;for(p=a0;pa0+9;p+)/*最后一个元素的地址是最后一个元素的地址是a0+8*/if(p-a0)%3=0)printf(n);/*换行控制换行控制*/printf(%5d,*p);下一页下一页返返 回回上一页上一页8.2 指针与数组指针与数组printf(n);程序运行结果:程序运行结果:a0是数组的第一个元素的地址,且基类型与指针是数组的第一个元素的地址,且基类型与指针p的基类型一致都的基类型一致都是是int型,所以用型,所以用p=a0使指针使指针p指向数组的第一个元素,这个表达式指向数组的第一个元素,这个表达式还可用还可用p=&a00代替,同样代替,同样a0+8也等价于也等价于&a00+8。下一页下一页返返 回回上一页上一页8.2 指针与数组指针与数组3.指向二维数组的行指针变量(行指针)指向二维数组的行指针变量(行指针)行指针变量就是用来存放行指针变量就是用来存放行行地址的变量,一般定义形式为:地址的变量,一般定义形式为:数据类型名数据类型名(*指针变量名)指针变量名)数组长度数组长度;例如:例如:int (*p)4;p是一个指针变量,它的基类型是一个包含是一个指针变量,它的基类型是一个包含4个整型元素的一维数组,个整型元素的一维数组,因此指针变量因此指针变量p可以指向一个有可以指向一个有4个元素的一维数组。个元素的一维数组。【例【例8-6】利用行指针输出二维数组元素的值。】利用行指针输出二维数组元素的值。【程序代码】【程序代码】#include void main()int a33=1,2,3,4,5,6,7,8,9;int (*p)3,j;/*指针变量指针变量p为行指针为行指针*/下一页下一页返返 回回上一页上一页8.2 指针与数组指针与数组for(p=a;pa+3;p+)for(j=0;j3;j+)printf(%5d,*(*p+j);printf(n);程序运行结果为:程序运行结果为:在此把数组在此把数组a看成是一维数组,它的元素有看成是一维数组,它的元素有a0、a1、a2。由于指。由于指针针p与数组名与数组名a表示的地址常量的基类型相同,所以可以用表示的地址常量的基类型相同,所以可以用p=a,它使,它使指针指针p指向了数组指向了数组a的第一个元素的第一个元素a0,这时,这时*p表示是表示是a0的值,即为的值,即为第第0行的首地址,如有行的首地址,如有*p+1,它表示,它表示a01的地址,的地址,*(*p+1)表示)表示数组元素数组元素a01。p+执行一次,指针执行一次,指针p向后移动一行向后移动一行 下一页下一页返返 回回上一页上一页8.2 指针与数组指针与数组4.指针数组指针数组比如有如下定义:比如有如下定义:int a34,*p3;数组数组p是一个包含是一个包含3个元素的一维数组,它的每个元素都是基类型为个元素的一维数组,它的每个元素都是基类型为int的指针,所以称数组的指针,所以称数组p为指针数组。为指针数组。pi和和ai(0i3)的基类型相同的基类型相同(都为(都为int类型),因此赋值语句类型),因此赋值语句pi=ai;是合法的。比如有以下循是合法的。比如有以下循环语句:环语句:for(i=0;i3;i+)pi=ai;该语句执行完后,数组该语句执行完后,数组p的的3个元素个元素p0、p1和和p2分别指向数组分别指向数组a每每行的开头,如行的开头,如图图8-5所示。此时如果有语句所示。此时如果有语句printf(%d,%d,*p0,*(p0+1);,那么输出的是数组元素,那么输出的是数组元素a00和和a01的值。的值。下一页下一页返返 回回上一页上一页8.2 指针与数组指针与数组8.2.3 指针与字符串指针与字符串字符数组通常用来存放字符串,指针指向字符数组也就指向了字符串,字符数组通常用来存放字符串,指针指向字符数组也就指向了字符串,因此通过指针可以引用它所指向的字符串。因此通过指针可以引用它所指向的字符串。【例例8-7】通过指针引用字符串。通过指针引用字符串。【程序代码程序代码】#include void main()char str=BeiJing,*p;p=str;/*指针指针p指针字符串首部指针字符串首部*/printf(%sn,p);/*从字符串首字符开始输出,遇从字符串首字符开始输出,遇0结束结束*/下一页下一页返返 回回上一页上一页8.2 指针与数组指针与数组p+=3;/*移动指针移动指针p*/printf(%sn,p);/*从指针从指针p所指字符开始输出,遇所指字符开始输出,遇0结束结束*/程序运行结果为:程序运行结果为:指针先指向字符串首部,从此位置开始输出,遇到结束符指针先指向字符串首部,从此位置开始输出,遇到结束符0为止,为止,然后指针向后移动了然后指针向后移动了3个字符,从串中第个字符,从串中第4个字符开始输出,遇结束符个字符开始输出,遇结束符0为止。为止。【例【例8-8】利用指针实现两个字符串的连接。】利用指针实现两个字符串的连接。【编程思路】【编程思路】(1)指针)指针p指向第一个串的末尾(最后一个字符后面),指针指向第一个串的末尾(最后一个字符后面),指针q指向指向第二个串的首部。第二个串的首部。(2)将第二个串中字符依次放入第一个串后。)将第二个串中字符依次放入第一个串后。下一页下一页返返 回回上一页上一页8.2 指针与数组指针与数组【程序代码】【程序代码】#include#include void main()char str120,str210,*p,*q;printf(请输入两个字符串:请输入两个字符串:);gets(str1);gets(str2);p=str1+strlen(str1);/*p指向第一个串的末尾指向第一个串的末尾*/q=str2;/*q指向第二个串的首部指向第二个串的首部*/下一页下一页返返 回回上一页上一页8.2 指针与数组指针与数组while(*q!=0)/*如果第二个串未结束,继续执行如果第二个串未结束,继续执行*/*p=*q;p+;/*指针指针p向后移动向后移动*/q+;/*指针指针q 向后移动向后移动*/*p=0;/*串末尾加上结束标志串末尾加上结束标志*/printf(连接后新串为:连接后新串为:);puts(str1);程序运行结果为:程序运行结果为:返返 回回上一页上一页8.3 指针与函数指针与函数 8.3.1 变量地址作函数参数变量地址作函数参数调用函数时,通过函数的参数不仅能够传递普通的值,而且还能传递调用函数时,通过函数的参数不仅能够传递普通的值,而且还能传递地址值。当实参为一个地址时,形参必须是一个基类型与它相同的指地址值。当实参为一个地址时,形参必须是一个基类型与它相同的指针变量。针变量。【例例8-9】求两数之和。求两数之和。【程序代码程序代码】#include int add(int *x,int *y)/*形参为指针变量形参为指针变量*/int z;z=*x+*y;return z;返返 回回下一页下一页8.3 指针与函数指针与函数 void main()int a,b,sum;printf(请输入请输入2个整数:个整数:);scanf(%d%d,&a,&b);sum=add(&a,&b);/*实参为变量的地址(即指针)实参为变量的地址(即指针)*/printf(%d+%d=%dn,a,b,sum);程序运行结果:程序运行结果:下一页下一页返返 回回上一页上一页8.3 指针与函数指针与函数 程序分析:程序分析:调用调用add()函数时,实参是变量函数时,实参是变量a、b的地址,形参是两个指针变量,的地址,形参是两个指针变量,只有指针变量才能接收地址值。接收完毕后,形参指针只有指针变量才能接收地址值。接收完毕后,形参指针x指向了变量指向了变量a,形参指针形参指针y指向了变量指向了变量b,实参变量和形参指针间的关系如,实参变量和形参指针间的关系如图图8-6所示。所示。这样就可以在函数中通过指针变量访问实参变量单元。这样就可以在函数中通过指针变量访问实参变量单元。此例中通过传送地址,使形参指针指向了实参变量,这样使得在被调此例中通过传送地址,使形参指针指向了实参变量,这样使得在被调函数中通过形参来改变实参的值成为可能。同时,原来只能通过函数中通过形参来改变实参的值成为可能。同时,原来只能通过return语句返回一个函数值,利用传地址的形式,可以把两个或两个语句返回一个函数值,利用传地址的形式,可以把两个或两个以上的值从被调函数中返回到调用函数。以上的值从被调函数中返回到调用函数。【例【例8-10】调用】调用swap函数,交换主函数中变量函数,交换主函数中变量x和和y中的数据。中的数据。【程序代码】【程序代码】#include 下一页下一页返返 回回上一页上一页8.3 指针与函数指针与函数 void swap(int *a,int *b)int t;t=*a;*a=*b;*b=t;void main()int x,y;printf(请输入请输入2个整数:个整数:);scanf(%d%d,&x,&y);printf(1)x=%d,y=%dn,x,y);swap(&x,&y);printf(2)x=%d,y=%dn,x,y);下一页下一页返返 回回上一页上一页8.3 指针与函数指针与函数 程序运行结果:程序运行结果:小测验小测验如果将函数改为如下形式,程序还能实现变量如果将函数改为如下形式,程序还能实现变量x和和y互换吗?互换吗?void swap(int *a,int *b)int *t;t=a;a=b;b=t;下一页下一页返返 回回上一页上一页8.3 指针与函数指针与函数 8.3.2 数组名作函数参数数组名作函数参数数组名可以用作函数的形参和实参,例如下面程序片段:数组名可以用作函数的形参和实参,例如下面程序片段:用数组名作实参时,是把数组的首地址传送给形参数组,对应的形参用数组名作实参时,是把数组的首地址传送给形参数组,对应的形参数组接收传过来的是实参数组的首地址,这样形参数组与实参数组共数组接收传过来的是实参数组的首地址,这样形参数组与实参数组共占同一段内存区域。数组元素占同一段内存区域。数组元素a0与与b0共占一个存储单元,共占一个存储单元,a1与与b1共占一个存储单元,。引用形参数组元素的值也就是引用共占一个存储单元,。引用形参数组元素的值也就是引用实参数组元素的值,因此形参数组会影响实参数组。实参数组元素的值,因此形参数组会影响实参数组。下一页下一页返返 回回上一页上一页void main()int a5;f(a,5);v o i d f(i n t b5,int n)8.3 指针与函数指针与函数【例【例8-11】数组名作函数参数。】数组名作函数参数。【程序代码】【程序代码】#include void add(int a,int b)/*函数定义函数定义*/int i;for(i=0;i3;i+)ai=ai+bi;void main()int x3=1,2,3;下一页下一页返返 回回上一页上一页8.3 指针与函数指针与函数 int y3=4,5,6;int i;add(x,y);/*函数调用,实参为数组名函数调用,实参为数组名*/for(i=0;i3;i+)printf(%4d,xi);小测验小测验写出上面程序的输出结果。写出上面程序的输出结果。以上将实参数组和形参数组看成是共用存储空间,这样比较形象,读以上将实参数组和形参数组看成是共用存储空间,这样比较形象,读者容易理解。实际上能够接收并存放地址值的只能是指针变量,者容易理解。实际上能够接收并存放地址值的只能是指针变量,C编编译系统是将形参数组名处理成指针变量。译系统是将形参数组名处理成指针变量。下一页下一页返返 回回上一页上一页8.3 指针与函数指针与函数 假设某函数首部为:假设某函数首部为:int add(int a,int b)在编译时系统会处理为:在编译时系统会处理为:int fun(int *a,int *b)调用函数时,指针变量接收从主调函数传递过来的实参数组首地址,调用函数时,指针变量接收从主调函数传递过来的实参数组首地址,这样形参指针指向了实参数组,那么可以通过形参指针去访问实参数这样形参指针指向了实参数组,那么可以通过形参指针去访问实参数组元素。组元素。提示:形参数组如果是一维数组,定义时大小可以不指定;如果是二维数组,提示:形参数组如果是一维数组,定义时大小可以不指定;如果是二维数组,第一维的大小可以不指定。第一维的大小可以不指定。【例例8-12】在数组中第在数组中第k个数前插入一个数个数前插入一个数x。【编程思路编程思路】(1)函数需要)函数需要4个形参,分别接收:实参数组地址、实参数组大小、个形参,分别接收:实参数组地址、实参数组大小、k、x。下一页下一页返返 回回上一页上一页8.3 指针与函数指针与函数(2)函数中的操作:)函数中的操作:指针指向最后一个元素。指针指向最后一个元素。从最后一个元素一直到下标为从最后一个元素一直到下标为k-1的元素,依次往后移。的元素,依次往后移。将将x赋给下标为赋给下标为k-1的元素。的元素。【程序代码】【程序代码】#include void fun(int *b,int n,int k,int x)int i;for(i=n-1;i=k-1;i-)/*从最后一个元素到第从最后一个元素到第k个元素,依次往后个元素,依次往后移移*/*(b+i+1)=*(b+i);下一页下一页返返 回回上一页上一页8.3 指针与函数指针与函数*(b+k-1)=x;/*将将x插入插入*/void main()int a9=1,2,3,4,5,6,7,8,k,x,i;printf(数组原值:数组原值:);for(i=0;i8;i+)printf(%6d,ai);printf(n请输入在第几位插入:请输入在第几位插入:);scanf(%d,&k);printf(请输入插入的数据:请输入插入的数据:);scanf(%d,&x);下一页下一页返返 回回上一页上一页8.3 指针与函数指针与函数 fun(a,8,k,x);/*函数调用函数调用*/printf(插入插入%d后数组值:后数组值:,x);for(i=0;i=k-1;i-)*(b+i+1)=*(b+i);*(b+k-1)=x;可以改写成下面语句形式,这样更清晰、简练。可以改写成下面语句形式,这样更清晰、简练。for(i=n-1;i=k-1;i-)bi+1=bi;bk-1=x;返返 回回8.4 指针应用实例指针应用实例【例【例8-14】利用指针实现把数组中的奇数存入另一数组中。】利用指针实现把数组中的奇数存入另一数组中。【编程思路】【编程思路】(1)用两个指针)用两个指针p和和q分别指向数组分别指向数组a和和b。(2)利用指针移动逐个取出数组)利用指针移动逐个取出数组a中的每个元素,如果当前元素的值中的每个元素,如果当前元素的值为奇数,则存入数组为奇数,则存入数组b中。中。【程序代码】【程序代码】#include void main()int a8,b8,*p,*q,i;printf(请给请给a数组中输入数组中输入8个整数:个整数:);for(i=0;i8;i+)下一页下一页返返 回回8.4 指针应用实例指针应用实例scanf(%d,&ai);q=b;/*指针指针q指向数组指向数组b*/for(p=a;pa+8;p+)if(*p%2!=0)*q=*p;/*如果如果p所指向的是奇数,则存入所指向的是奇数,则存入b数组数组中中*/q+;/*指针指针q指向指向b数组中下一个元素数组中下一个元素*/printf(b数组中的值为:数组中的值为:);for(i=0;iq-b;i+)/*q当前指向当前指向b数组中最后一个数值的后面,数组中最后一个数值的后面,q-b为为b数组所存数值的个数数组所存数值的个数*/printf(%dt,bi);下一页下一页返返 回回上一页上一页8.4 指针应用实例指针应用实例printf(n);程序运行结果:程序运行结果:b数组虽然有个元素,但只有前个元素中有确切的值。数组虽然有个元素,但只有前个元素中有确切的值。【例【例8-15】先将在字符串】先将在字符串s中的字符按正序存放到中的字符按正序存放到t串中,然后把串中,然后把s中的中的字符按逆序连接到字符按逆序连接到t串的后面。串的后面。例如:当例如:当s中的字符串为:中的字符串为:ABCDE时,则时,则t中的字符串应为:中的字符串应为:ABCDEEDCBA。下一页下一页返返 回回上一页上一页8.4 指针应用实例指针应用实例【编程思路】通过指针先由前往后访问【编程思路】通过指针先由前往后访问s串,并逐个字符存入串,并逐个字符存入t串中;再串中;再由后往前访问由后往前访问s串,并逐个字符存入串,并逐个字符存入t串中,最后输出串中,最后输出t串即可。串即可。#include#include void main()char s20,t20,*p,*q;printf(请输入一个字符串:请输入一个字符串:);gets(s);for(p=s,q=t;*p!=0;p+,q+)/*正序存放正序存放*/*q=*p;for(p-;p=s;p-,q+)/*p由后向前访问由后向前访问s串,实现逆序连接串,实现逆序连接*/下一页下一页返返 回回上一页上一页8.4 指针应用实例指针应用实例*q=*p;*q=0;puts(t);程序运行结果:程序运行结果:【例【例8-16】编写函数,其功能是对传送过来的两个浮点数求出和值与】编写函数,其功能是对传送过来的两个浮点数求出和值与差值,并通过形参传送回调用函数。差值,并通过形参传送回调用函数。【编程思路】【编程思路】(1)定义变量)定义变量a、b存放两个浮点数,变量存放两个浮点数,变量sum、sub存放两数的和与存放两数的和与差。差。下一页下一页返返 回回上一页上一页8.4 指针应用实例指针应用实例(2)被调函数)被调函数fun中,需要两个中,需要两个float类型的形参类型的形参x、y来接收两个实数,来接收两个实数,还需要两个指针还需要两个指针s、n,一个指向,一个指向sum,一个指向,一个指向sub。(3)函数)函数fun中中,计算的两数和放到计算的两数和放到s所指向的变量所指向的变量sum,两数差放到,两数差放到n所指向的变量所指向的变量sub中。中。【程序代码】【程序代码】#include void fun(float x,float y,float *s,float *n)*s=x+y;/*将和放入将和放入s所指向的存储单元所指向的存储单元*/*n=x-y;/*将差放入将差放入n所指向的存储单元所指向的存储单元*/void main()下一页下一页返返 回回上一页上一页8.4 指针应用实例指针应用实例float a,b,sum,sub;a=10.5;b=20.8;fun(a,b,&sum,&sub);printf(%.2f+%.2f=%.2fn,a,b,sum);printf(%.2f-%.2f=%.2fn,a,b,sub);程序运行结果:程序运行结果:下一页下一页返返 回回上一页上一页8.4 指针应用实例指针应用实例【例【例8-17】将字符串从第】将字符串从第k个字符起,删去个字符起,删去m个字符,组成新字符串。个字符,组成新字符串。【编程思路】【编程思路】(1)函数需要)函数需要3个形参,分别接收串的首地址、个形参,分别接收串的首地址、k值和值和m值。值。(2)函数中的操作:)函数中的操作:指针指针p指向第指向第k个字符,指针个字符,指针q指向第指向第k+m个字符。个字符。赋值赋值*p=*q。指针指针p、q同时向后移,返回(同时向后移,返回(2),直到),直到q指向串结束标志。指向串结束标志。【程序代码】【程序代码】#include void del(char *s,int k,int m)char *p,*q;下一页下一页返返 回回上一页上一页8.4 指针应用实例指针应用实例p=s+k-1;/*p指向第指向第k个字符个字符*/q=s+k+m-1;/*指针指针q指向第指向第k+m个字符个字符*/while(*q!=0)*p+=*q+;/*赋值并且移动指针赋值并且移动指针*/*p=0;void main()char str30;int k,m;printf(请输入字符串:请输入字符串:);gets(str);下一页下一页返返 回回上一页上一页上一页上一页8.4 指针应用实例指针应用实例printf(请输入从第几个字符开始删除:请输入从第几个字符开始删除:);scanf(%d,&k);printf(请输入删除几个字符:请输入删除几个字符:);scanf(%d,&m);del(str,k,m);printf(删除后字符串:删除后字符串:);puts(str);程序运行结果:程序运行结果:返返 回回8.5 本章小结本章小结1.每个变量都有地址(即指针),指针变量用于存放其他变量的地址。每个变量都有地址(即指针),指针变量用于存放其他变量的地址。2.指针变量与普通变量一样,要先定义后使用。如有定义语句指针变量与普通变量一样,要先定义后使用。如有定义语句float*fp;,则,则fp只能指向只能指向float类型的变量。类型的变量。3.建立指针的指向关系,可以通过以下语句完成:建立指针的指向关系,可以通过以下语句完成:(1)指针变量)指针变量=&变量;变量;(2)指针变量)指针变量1=指针变量指针变量2;,其中指针变量;,其中指针变量2为已有指向的指针变为已有指向的指针变量。量。4.变量的访问。变量可以通过变量名直接访问,也可以利用指针间接变量的访问。变量可以通过变量名直接访问,也可以利用指针间接访问,访问,*指针变量指针变量表示指针变量所指向的变量。表示指针变量所指向的变量。5.指针与一维数组。当指针变量指针与一维数组。当指针变量p指向数组时,可以通过指向数组时,可以通过p的自增和自的自增和自减在数组区域内移动指针,方便地访问数组的各个元素。减在数组区域内移动指针,方便地访问数组的各个元素。下一页下一页返返 回回上一页上一页8.5 本章小结本章小结6.指针与二维数组。二维数组的指针比较复杂,根据定义的指针类型,指针与二维数组。二维数组的指针比较复杂,根据定义的指针类型,可分为列指针和行指针。列指针为数组元素地址,可以在数组元素间可分为列指针和行指针。列指针为数组元素地址,可以在数组元素间移动,行指针为各行首地址,只能在行间移动。二维数组名是行指针移动,行指针为各行首地址,只能在行间移动。二维数组名是行指针常量。常量。7.指针与函数。用指针作函数参数时,可以在被调函数中访问调用函指针与函数。用指针作函数参数时,可以在被调函数中访问调用函数中的变量,为问题的处理提供了方便。函数间参数传递方式见数中的变量,为问题的处理提供了方便。函数间参数传递方式见表表8-3。运用指针编程是运用指针编程是C语言主要风格之一。利用指针能方便地处理数组和语言主要风格之一。利用指针能方便地处理数组和字符串。不可否认指针也是字符串。不可否认指针也是C语言学习中最难理解和使用的部分,学语言学习中最难理解和使用的部分,学习中除了要正确理解指针的基本概念外,还需要多编写程序,多上机习中除了要正确理解指针的基本概念外,还需要多编写程序,多上机调试。调试。返返 回回8.6 实训实训 实训实训1【实训内容实训内容】指针和指针变量。指针和指针变量。【实训目的实训目的】掌握指针和指针变量的使用。掌握指针和指针变量的使用。【实训题目实训题目】编写程序,实现以下的每一步操作,并写出输出结果,编写程序,实现以下的每一步操作,并写出输出结果,然后上机验证。然后上机验证。(1)定义整型变量)定义整型变量x,并赋初值,并赋初值4321。(2)定义指向整型变量的指针变量)定义指向整型变量的指针变量p和和q,并使,并使p指向变量指向变量x。(3)通过指针变量)通过指针变量p使使q指向变量指向变量x。(4)通过)通过p对对x中的值增加中的值增加111。(5)通过)通过q求求x中的值的个位数,并把结果存放在中的值的个位数,并把结果存放在p所指向的存储单元所指向的存储单元中。中。(6)通过)通过x输出该变量中的值。输出该变量中的值。下一页下一页返返 回回8.6 实训实训 实训实训2【实训内容实训内容】指针作为函数参数。指针作为函数参数。【实训目的实训目的】掌握函数间的地址传递。掌握函数间的地址传递。【实训题目实训题目】分析下列程序,写出输出结果,然后上机进行验证。分析下列程序,写出输出结果,然后上机进行验证。#include void fun(int x,int y,int *cp,int *dp)*cp=x+y;*dp=x-y;下一页下一页返返 回回上一页上一页8.6 实训实训void main()int a,b,c,d;a=4;b=3;fun(a,b,&c,&d);printf(%d,%dn,c,d);下一页下一页返返 回回上一页上一页8.6 实训实训 实训实训3【实训内容实训内容】数组名作为函数参数。数组名作为函数参数。【实训目的实训目的】掌握数组作为函数参数的使用。掌握数组作为函数参数的使用。【实训题目实训题目】编写程序,交换数组编写程序,交换数组a和数组和数组b中的对应元素,要求数组中的对应元素,要求数组交换功能在函数中实现。主函数已给出,请补充交换功能在函数中实现。主函数已给出,请补充reverse()函数。函数。#include void reverse(int x,int y,int n)void main()int a10,b10,i;printf(请输入请输入10个数给数组个数给数组a:);for(i=0;i10;i+)下一页下一页返返 回回上一页上一页8.6 实训实训scanf(%d,&ai);printf(请输入请输入10个数给数组个数给数组b:);for(i=0;i10;i+)scanf(%d,&bi);reverse(a,b,10);printf(互换后数组互换后数组a的值:的值:);for(i=0;i10;i+)printf(%6d,ai);printf(n互换后数组互换后数组b的值:的值:);for(i=0;i10;i+)printf(%6d,bi);printf(n);下一页下一页返返 回回上一页上一页8.6 实训实训 实训实训4【实训内容实训内容】字符串与指针。字符串与指针。【实训目的实训目的】掌握指针在字符串操作中的应用。掌握指针在字符串操作中的应用。【实训题目实训题目】给定程序中函数给定程序中函数fun()的功能是:从字符串的功能是:从字符串s尾部开始尾部开始,按按逆序把在其中出现的每相邻的两个字符,紧随其后重复出现一次,放逆序把在其中出现的每相邻的两个字符,紧随其后重复出现一次,放在一个新串在一个新串t中,若字符串中,若字符串s中头部有剩余的单个字符也重复,放在中头部有剩余的单个字符也重复,放在t的的最后。最后。例如:当例如:当s中的字符串为:中的字符串为:ABCDE时,时,则则t中的字符串应为:中的字符串应为:EDEDCBCBAA。请改正函数请改正函数fun中的错误,使它能得出正确的结果。注意:不要改动中的错误,使它能得出正确的结果。注意:不要改动main函数,不得增行或删行,也不得更改程序的结构!函数,不得增行或删行,也不得更改程序的结构!#include 下一页下一页返返 回回上一页上一页8.6 实训实训#include void fun(char *s,char *t)int i,j,sl;sl=strlen(s);/*found*/for(i=sl,j=0;i=0;i-=2)tj+=si;if(i-1=0)tj+=si-1;tj+=si;下一页下一页返返 回回上一页上一页上一页上一页8.6 实训实训/*found*/if(i-1=0)ti+=si-1;tj=0;void main()char s100,t100;printf(nPlease enter string s:);scanf(%s,s);fun(s,t);printf(The result is:%sn,t);返返 回回图图8-1 p指向指向a返返 回回图图8-2 指针移动示意指针移动示意返返 回回图图8-3 指针指针p指向数组指向数组返返 回回表表8-1一维数组元素的地址一维数组元素的地址返返 回回a0地址地址a1地址地址ai地址地址通过取地址符通过取地址符&a0&a1&ai通过数组名通过数组名aaa+1a+i通过指针变量通过指针变量ppp+1p+i提示:对指针变量提示:对指针变量p更多的是通过更多的是通过p+或或p-移动定位。移动定位。表表8-2 一维数组元素一维数组元素返返 回回a0地址地址a1地址地址ai地址地址通过数组元素名通过数组元素名a0a1ai通过数组名通过数组名a*a*(a+1)*(a+i)通过指针变量通过指针变量p*p*(p+1)*(p+i)下标法下标法p0p1pi图图8-4 二维数组地址示意二维数组地址示意返返 回回图图8-5 指针数组指向示意指针数组指向示意返返 回回图图8-6 函数间地址传递函数间地址传递返返 回回表表8-3 函数间参数传递方式函数间参数传递方式返返 回回实实 参参形形 参参传递数据传递数据效效 果果变量变量常量常量表达式表达式变量变量值值形参不影响实参形参不影响实参指针(地址)指针(地址)指针变量指针变量指针变量指针变量地址值地址值形参影响实参形参影响实参数组名数组名数组数组指针变量指针变量地址值地址值形参影响实参形参影响实参
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 图纸专区 > 成人自考


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!