函数的参数传递.docx
- 文档编号:8287184
- 上传时间:2023-01-30
- 格式:DOCX
- 页数:16
- 大小:23.50KB
函数的参数传递.docx
《函数的参数传递.docx》由会员分享,可在线阅读,更多相关《函数的参数传递.docx(16页珍藏版)》请在冰豆网上搜索。
函数的参数传递
一、三道考题开讲之前,我先请你做三道题目。
(嘿嘿,得先把你的头脑搞昏才行……唉呀,谁扔我鸡蛋?
)
1.考题一:
程序代码如下:
voidExchg1(intx,inty)
{
inttmp;
tmp=x;
x=y;
y=tmp;
printf(“x=%d,y=%d\n”,x,y)
}
voidmain()
{
inta=4,b=6;
Exchg1(a,b);
printf(“a=%d,b=%d\n”,a,b)
}
输出的结果:
x=____,y=____
a=____,b=____
问下划线的部分应是什么,请完成。
2.考题二:
代码如下。
Exchg2(int*px,int*py)
{
inttmp=*px;
*px=*py;
*py=tmp;
print(“*px=%d,*py=%d\n”,*px,*py);
}
main()
{
inta=4;
intb=6;
Exchg2(&a,&b);
Print(“a=%d,b=%d\n”,a,b);
}
输出的结果为:
*px=____,*py=____
a=____,b=____
问下划线的部分应是什么,请完成。
3.考题三:
Exchg2(int&x,int&y)//这个好像是不能这样写得
{
inttmp=x;
x=y;
y=tmp;
print(“x=%d,y=%d\n”,x,y);
}
main()
{
inta=4;
intb=6;
Exchg2(a,b);
Print(“a=%d,b=%d\n”,a,b);
}
输出的结果:
x=____,y=____
a=____,b=____
问下划线的部分输出的应是什么,请完成。
你不在机子上试,能作出来吗?
你对你写出的答案有多大的把握?
正确的答案,想知道吗?
(呵呵,让我慢慢地告诉你吧!
)
好,废话少说,继续我们的探索之旅了。
我们都知道:
C语言中函数参数的传递有:
值传递,地址传递,引用传递这三种形式。
题一为值传递,题二为地址传递,题三为引用传递。
不过,正是这几种参数传递的形式,曾把我给搞得晕头转向。
我相信也有很多人与我有同感吧?
下面请让我逐个地谈谈这三种传递形式。
二、函数参数传递方式之一:
值传递
1.值传递的一个错误认识
先看题一中Exchg1函数的定义:
voidExchg1(intx,inty) //定义中的x,y变量被称为Exchg1函数的形式参数
{
inttmp;
tmp=x;
x=y;
y=tmp;
printf(“x=%d,y=%d\n”,x,y)
}
问:
你认为这个函数是在做什么呀?
答:
好像是对参数x,y的值对调吧?
请往下看,我想利用这个函数来完成对a,b两个变量值的对调,程序如下:
voidmain()
{
inta=4,b=6;
Exchg1(a,b) //a,b变量为Exchg1函数的实际参数。
/printf(“a=%d,b=%d\n”,a,b)
}
我问:
Exchg1()里头的printf(“x=%d,y=%d\n”,x,y)语句会输出什么啊?
我再问:
Exchg1()后的printf(“a=%d,b=%d\n”,a,b)语句输出的是什么?
程序输出的结果是:
x=6,y=4
a=4,b=6//为什么不是a=6,b=4呢?
奇怪,明明我把a,b分别代入了x,y中,并在函数里完成了两个变量值的交换,为什么a,b变量值还是没有交换(仍然是a==4,b==6,而不是a==6,b==4)?
如果你也会有这个疑问,那是因为你跟本就不知实参a,b与形参x,y的关系了。
2.一个预备的常识
为了说明这个问题,我先给出一个代码:
inta=4;
intx;
x=a;
x=x+3;
看好了没,现在我问你:
最终a值是多少,x值是多少?
(怎么搞的,给我这个小儿科的问题。
还不简单,不就是a==4x==7嘛!
)
在这个代码中,你要明白一个东西:
虽然a值赋给了x,但是a变量并不是x变量哦。
我们对x任何的修改,都不会改变a变量。
呵呵!
虽然简单,并且一看就理所当然,不过可是一个很重要的认识喔。
3.理解值传递的形式
看调用Exch1函数的代码:
main()
{
inta=4,b=6;
Exchg1(a,b)//这里调用了Exchg1函数
printf(“a=%d,b=%d”,a,b)
}
Exchg1(a,b)时所完成的操作代码如下所示。
intx=a;//←
inty=b;//←注意这里,头两行是调用函数时的隐含操作
inttmp;
tmp=x;
x=y;
y=tmp;
请注意在调用执行Exchg1函数的操作中我人为地加上了头两句:
intx=a;
inty=b;
这是调用函数时的两个隐含动作。
它确实存在,现在我只不过把它显式地写了出来而已。
问题一下就清晰起来啦。
(看到这里,现在你认为函数里面交换操作的是a,b变量或者只是x,y变量呢?
)
原来,其实函数在调用时是隐含地把实参a,b的值分别赋值给了x,y,之后在你写的Exchg1函数体内再也没有对a,b进行任何的操作了。
交换的只是x,y变量。
并不是a,b.当然a,b的值没有改变啦!
函数只是把a,b的值通过赋值传递给了x,y,函数里头操作的只是x,y的值并不是a,b的值。
这就是所谓的参数的值传递了。
哈哈,终于明白了,正是因为它隐含了那两个的赋值操作,才让我们产生了前述的迷惑(以为a,b已经代替了x,y,对x,y的操作就是对a,b的操作了,这是一个错误的观点啊!
)。
指向另一指针的指针
一、针概念:
早在本系列第二篇中我就对指针的实质进行了阐述。
今天我们又要学习一个叫做指向另一指针地址的指针。
让我们先回顾一下指针的概念吧!
当我们程序如下申明变量:
shortinti;
chara;
shortint*pi;
程序会在内存某地址空间上为各变量开辟空间,如下图所示。
内存地址→6 7 8 9 10 11 12 13 14 15
-------------------------------------------------------------------------------------
… | | | | | | | | | |
-------------------------------------------------------------------------------------
|shortinti|chara| |shortint*pi|
图中所示中可看出:
i变量在内存地址5的位置,占两个字节。
a变量在内存地址7的位置,占一个字节。
pi变量在内存地址9的位置,占两个字节。
(注:
pi是指针,我这里指针的宽度只有两个字节,32位系统是四个字节)
接下来如下赋值:
i=50;
pi=&i;
经过上在两句的赋值,变量的内存映象如下:
内存地址→6 7 8 9 10 11 12 13 14 15
--------------------------------------------------------------------------------------
… | 50 | | | 6 | | | |
--------------------------------------------------------------------------------------
|shortinti|chara| |shortint*pi|
看到没有:
短整型指针变量pi的值为6,它就是I变量的内存起始地址。
所以,这时当我们对*pi进行读写操作时,其实就是对i变量的读写操作。
如:
*pi=5; //就是等价于I=5;
你可以回看本系列的第二篇,那里有更加详细的解说。
二、指针的地址与指向另一指针地址的指针
在上一节中,我们看到,指针变量本身与其它变量一样也是在某个内存地址中的,如pi的内存起始地址是10.同样的,我们也可能让某个指针指向这个地址。
看下面代码:
shortint**ppi; //这是一个指向指针的指针,注意有两个*号
ppi=π
第一句:
shortint**ppi;——申明了一个指针变量ppi,这个ppi是用来存储(或称指向)一个shortint*类型指针变量的地址。
第二句:
&pi那就是取pi的地址,ppi=π就是把pi的地址赋给了ppi.即将地址值10赋值给ppi.如下图:
内存地址→6 7 8 9 10 11 12 13 14 15
------------------------------------------------------------------------------------
… | 50 | | | 6 | 10 | |
------------------------------------------------------------------------------------
|shortinti|chara| |shortint*pi|shortint**ppi|
从图中看出,指针变量ppi的内容就是指针变量pi的起始地址。
于是……
ppi的值是多少呢?
——10.
*ppi的值是多少呢?
——6,即pi的值。
**ppi的值是多少呢?
——50,即I的值,也是*pi的值。
呵呵!
不用我说太多了,我相信你应明白这种指针了吧!
三、一个应用实例
1.设计一个函数:
voidfind1(chararray[],charsearch,char*pi)
要求:
这个函数参数中的数组array是以0值为结束的字符串,要求在字符串array中查找字符是参数search里的字符。
如果找到,函数通过第三个参数(pa)返回值为array字符串中第一个找到的字符的地址。
如果没找到,则为pa为0.
设计:
依题意,实现代码如下
voidfind1(char[]array,charsearch,char*pa)
{
inti;
for(i=0;*(array+i)!
=0;i++)
{
if(*(array+i)==search)
{
pa=array+i
break;
}
elseif(*(array+i)==0)
{
pa=0;
break;
}
}
}
你觉得这个函数能实现所要求的功能吗?
调试:
我下面调用这个函数试试。
voidmain()
{
charstr[]={“afsdfsdfdf\0”};//待查找的字符串
chara=’d’; //设置要查找的字符
char*p=0;//如果查找到后指针p将指向字符串中查找到的第一个字符的地址。
find1(str,a,p);//调用函数以实现所要操作。
if(0==p)
{
printf(“没找到!
\n”);//1.如果没找到则输出此句
}
else
{
printf(“找到了,p=%d”,p);//如果找到则输出此句
}
}
分析:
上面代码,你认为会是输出什么呢?
运行试试。
唉!
怎么输出的是:
没有找到!
而不是:
找到了,……。
明明a值为‘d’,而str字符串的第四个字符是‘d’,应该找得到呀!
再看函数定义处:
voidfind1(char[]array,charsearch,char*pa)
看调用处:
find1(str,a,p);
依我在第五篇的分析方法,函数调用时会对每一个参数进行一个隐含的赋值操作。
整个调用如下:
array=str;
search=a;
pa=p; //请注意:
以上三句是调用时隐含的动作。
inti;
for(i=0;*(array+i)!
=0;i++)
{
if(*(array+i)==search)
{
pa=array+i
break;
}
elseif(*(array+i)==0)
{
pa=0;
break;
}
}
哦!
参数pa与参数search的传递并没有什么不同,都是值传递嘛(小语:
地址传递其实就是地址值传递嘛)!
所以对形参变量pa值(当然值是一个地址值)的修改并不会改变实参变量p值,因此p的值并没有改变(即p的指向并没有被改变)。
(如果还有疑问,再看一看《第五篇:
函数参数的传递》了。
)
修正:
voidfind2(char[]array,charsearch,char**ppa)
{
inti;
for(i=0;*(array+i)!
=0;i++)
{
if(*(array+i)==search)
{
*ppa=array+i
break;
}
elseif(*(array+i)==0)
{
*ppa=0;
break;
}
}
}
主函数的调用处改如下:
find2(str,a,&p);//调用函数以实现所要操作。
再分析:
这样调用函数时的整个操作变成如下:
array=str;
search=a;
ppa=&p; //请注意:
以上三句是调用时隐含的动作。
inti;
for(i=0;*(array+i)!
=0;i++)
{
if(*(array+i)==search)
{
*ppa=array+i
break;
}
elseif(*(array+i)==0)
{
*ppa=0;
break;
}
}
看明白了吗?
ppa指向指针p的地址。
对*ppa的修改就是对p值的修改。
你自行去调试。
经过修改后的程序就可以完成所要的功能了。
看懂了这个例子,也就达到了本篇所要求的目的。
函数名与函数指针
一数调用
一个通常的函数调用的例子:
//自行包含头文件
voidMyFun(intx); //此处的申明也可写成:
voidMyFun(int);
intmain(intargc,char*argv[])
{
MyFun(10); //这里是调用MyFun(10);函数
return0;
}
voidMyFun(intx)//这里定义一个MyFun函数
{
printf(“%d\n”,x);
}
这个MyFun函数是一个无返回值的函数,它并不完成什么事情。
这种调用函数的格式你应该是很熟悉的吧!
看主函数中调用MyFun函数的书写格式:
MyFun(10);
我们一开始只是从功能上或者说从数学意义上理解MyFun这个函数,知道MyFun函数名代表的是一个功能(或是说一段代码)。
直到——
学习到函数指针概念时。
我才不得不在思考:
函数名到底又是什么东西呢?
(不要以为这是没有什么意义的事噢!
呵呵,继续往下看你就知道了。
)
二函数指针变量的申明
就象某一数据变量的内存地址可以存储在相应的指针变量中一样,函数的首地址也以存储在某个函数指针变量里的。
这样,我就可以通过这个函数指针变量来调用所指向的函数了。
在C系列语言中,任何一个变量,总是要先申明,之后才能使用的。
那么,函数指针变量也应该要先申明吧?
那又是如何来申明呢?
以上面的例子为例,我来申明一个可以指向MyFun函数的函数指针变量FunP.下面就是申明FunP变量的方法:
void(*FunP)(int); //也可写成void(*FunP)(intx);
你看,整个函数指针变量的申明格式如同函数MyFun的申明处一样,只不过——我们把MyFun改成(*FunP)而已,这样就有了一个能指向MyFun函数的指针FunP了。
(当然,这个FunP指针变量也可以指向所有其它具有相同参数及返回值的函数了。
)
三通过函数指针变量调用函数
有了FunP指针变量后,我们就可以对它赋值指向MyFun,然后通过FunP来调用MyFun函数了。
看我如何通过FunP指针变量来调用MyFun函数的:
//自行包含头文件
voidMyFun(intx); //这个申明也可写成:
voidMyFun(int);
void(*FunP)(int); //也可申明成void(*FunP)(intx),但习惯上一般不这样。
intmain(intargc,char*argv[])
{
MyFun(10); //这是直接调用MyFun函数
FunP=&MyFun;//将MyFun函数的地址赋给FunP变量
(*FunP)(20); //这是通过函数指针变量FunP来调用MyFun函数的。
}
voidMyFun(intx)//这里定义一个MyFun函数
{
printf(“%d\n”,x);
}
请看黑体字部分的代码及注释。
运行看看。
嗯,不错,程序运行得很好。
哦,我的感觉是:
MyFun与FunP的类型关系类似于int与int*的关系。
函数MyFun好像是一个如int的变量(或常量),而FunP则像一个如int*一样的指针变量。
inti,*pi;
pi=&i; //与FunP=&MyFun比较。
(你的感觉呢?
)
呵呵,其实不然——
四调用函数的其它书写格式
函数指针也可如下使用,来完成同样的事情:
//自行包含头文件
voidMyFun(intx);
void(*FunP)(int); //申明一个用以指向同样参数,返回值函数的指针变量。
intmain(intargc,char*argv[])
{
MyFun(10); //这里是调用MyFun(10);函数
FunP=MyFun;//将MyFun函数的地址赋给FunP变量
FunP(20); //这是通过函数指针变量来调用MyFun函数的。
return0;
}
voidMyFun(intx)//这里定义一个MyFun函数
{
printf(“%d\n”,x);
}
我改了黑体字部分(请自行与之前的代码比较一下)。
运行试试,啊!
一样地成功。
咦?
FunP=MyFun;
可以这样将MyFun值同赋值给FunP,难道MyFun与FunP是同一数据类型(即如同的int与int的关系),而不是如同int与int*的关系了?
(有没有一点点的糊涂了?
)
看来与之前的代码有点矛盾了,是吧!
所以我说嘛!
请容许我暂不给你解释,继续看以下几种情况(这些可都是可以正确运行的代码哟!
):
代码之三:
intmain(intargc,char*argv[])
{
MyFun(10); //这里是调用MyFun(10);函数
FunP=&MyFun;//将MyFun函数的地址赋给FunP变量
FunP(20); //这是通过函数指针变量来调用MyFun函数的。
return0;
}
代码之四:
intmain(intargc,char*argv[])
{
MyFun(10); //这里是调用MyFun(10);函数
FunP=MyFun;//将MyFun函数的地址赋给FunP变量
(*FunP)(20); //这是通过函数指针变量来调用MyFun函数的。
return0;
}
真的是可以这样的噢!
(哇!
真是要晕倒了!
)
还有呐!
看——
intmain(intargc,char*argv[])
{
(*MyFun)(10); //看,函数名MyFun也可以有这样的调用格式
return0;
}
你也许第一次见到吧:
函数名调用也可以是这样写的啊!
(只不过我们平常没有这样书写罢了。
)
那么,这些又说明了什么呢?
呵呵!
依据以往的知识和经验来推理本篇的“新发现”,我想就连“福尔摩斯”也必定会由此分析并推断出以下的结论:
1.其实,MyFun的函数名与FunP函数指针都是一样的,即都是函数指针。
MyFun函数名是一个函数指针常量,而FunP是一个函数数指针变量,这是它们的关系。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 函数 参数 传递