“函数参数传递”的个人总结,请大家拍砖!!!
鉴于很多人对“函数参数传递”这一块不理解,比如问int &a与int*&a的区别等等,我根据自己的理解,以容易理解的方式总结了一下,总共有八种(可能还有)。这只是我能想到了的。请大家继续多多指教,拍砖也可以!
另外声明:为了便于解释,我把讲解都以注释的形式写在程序中了。不习惯的人就迁就看吧!
#include <iostream>
using namespace std;
/*为了便于区分讲解,函数中的临时参数标识符不用void fun1(int x,int y)代码中的x,y而用a与b替换
*另外,程序解释不用太多的语法,用通俗的话语依旧可以很有趣。“千言万语不如一个好例子”。下面
*我就遵循这个原则去解释我对问题的理解。
*/
/*fun1中的参数ab是在函数fun1调用的时候才分配内存单元,也就是临时变量,在函数调用结束后
*自动销毁。当调用fun1(x,y)时,实际相当于fun1(int a=x,int b=y)或者fun1(int a=*x0,int b=*y0);
*因此ab有自己的内存,通过调用ab也有了自己的值,那么在函数中无论对ab的什么操作,都只影响到ab,
*而与xy无关。
*用一个比喻更好解释:假设我国要引进俄国某个机型的战斗机生产线,那么通过政府(main())批准审核投资
*这个生产线就建造成了(fun1());那么这个生产线与俄国内的同样的生产线之间是相互独立的
*(ab与xy的区别),唯一的联系是:通过政府(main())出钱购买他们的技术或者设配(调用,同时a=x,b=y)
*经过这样之后,我们无论在这个生产线上造什么牛逼的歼十,十一。都与俄国本部的生产线无关了,他们关不
*着也问不着!
*/
void fun1(int a,int b)
{//这个函数交换数值是:治标不治本
int tem;
tem=a;
a=b;
b=tem;
cout<<"fun1(int a,int b):a="<<a<<",b="<<b<<endl;
}
/*fun2数值的交换效果依旧是治标不治本。而且要注意它与fun3的区别,虽然它们形参格式相同
*临时开辟三个临时指针,a、b、tem。同样三者都是局部变量,与函数“老大”“同年同月同日同时生”
*而且“同年同月同日同时死”(很像三国的桃园三结义,都是忠诚的卫士)。fun2中的指针ab存储的
*是x,y的地址,等价于fun2(int *a=&x,int *b=&y)或者fun2(int *a=x0,int *b=y0);fun2中的代码
*实现的是把指针ab存的地址值交换一下,实质是交换了ab指针的指向,因此ab存储的地址中存储
*值还是没有改变。而且也不影响外界指针x0y0的指向,在fun7中会看到与不同
*可以通过fun2中注释掉的语句验证一下
*/
void fun2(int *a,int *b)
{
//cout<<"a存的地址值"<<a<<"\nb存的地址值"<<b<<endl;
//cout<<"a指向的值"<<*a<<"\nb指向的值"<<*b<<endl;
int *tem;
tem=a;
a=b;
b=tem;
cout<<"fun2(int *a,int *b):*a="<<*a<<",*b="<<*b<<endl;
//cout<<"a存的地址值"<<a<<"\nb存的地址值"<<b<<endl;
//cout<<"a指向的值"<<*a<<"\nb指向的值"<<*b<<endl;
}
/*fun3交换数值的效果才算治本了!
*局部变量问题不再解释。通过临时指针ab中存储的地址,找到真正要交换的xy值,然后把他们交换了!
*公安局喜欢这样干活,他们总是不能直接找到犯罪主谋,但是他们会找到一些知道主谋线索的其他非主谋
*嫌疑犯,那么通过抓住他们然后用刑折磨,这要比直接找主谋要容易些,当然这样做有些曲折(绕弯)!但也很有效
*同理,假设你在家里建一个小金库(这里的xy),那么你要设置好自己的密码(xy的地址),然后死死地
*记在脑海(指针)中。每当想打开看看让自己踏实些,你就要从脑海中找到这个密码然后打开它。然而技术
*在飞跃,假设已有《盗梦空间》中的技术,我想改变你的意念(fun3)或者从梦中偷你的思想或者秘密
*接下来的情节会更精彩...
*/
void fun3(int *a,int *b)
{
int tem;
tem=*a;
*a=*b;
*b=tem;
cout<<"fun3(int *a,int *b):*a="<<*a<<",*b="<<*b<<endl;
}
/*fun4表述的是“引用”
*引用的通俗解释:相当于一个人有多个名字或者外号一样。无论你叫他哪个名字,他都应。
*因此引用很像:一个变量有多个标识符(这样说稍微有些不当)。如果a是变量b的引用,那么ab是同一对象
*通过调用fun4(x,y)或者fun4(*x0,*y0).那么临时变量ab分别是xy与*x0与*y0的引用了。对ab操作就相当于在
*main中直接操作xy
*/
void fun4(int &a,int &b)
{
int tem;
tem=a;
a=b;
b=tem;
cout<<"fun4(int &a,int &b):a="<<a<<",b="<<b<<endl;
}
/*fun5参数采用指向指针的指针,这比fun2,fun3还要绕弯子,但这里依旧要注意fun5与fun7的区别
*fun5依旧治标不治本,fun6才能治本,他们实质和fun2与fun3类似,只不过比它们要多一层指针
*既然多一层指针那么在调用的时候传递的实参就必须是指针的地址,而不能是别的。等价于
*fun5(int **a=&x0,int **b=&y0)
*换用上面的比喻:相当于在《盗梦空间》里进入第二层梦里偷意念了。c++里没有拓展到第三,四层梦里
*去偷东西!也就是没有***a或者*****a。因为两层处理的很好了!
*/
void fun5(int **a,int **b)
{
int **tem;
tem=a;
a=b;
b=tem;
cout<<"fun5(int **a,int **b):**a="<<**a<<",**b="<<**b<<endl;
}
/*fun6和fun3有相同的实质,只是多一层指针
*/
void fun6(int **a,int **b)
{
int tem;
tem=**a;
**a=**b;
**b=tem;
cout<<"fun6(int **a,int **b):**a="<<**a<<",**b="<<**b<<endl;
}
/*fun7实现与fun2不同效果,上面我已经提到了。
*fun2结果是函数内部的交换不会影响到外面指针的指向,但是这里不同了,fun7函数实现了指针x0y0
*指向的交换。但却没有影响到xy的值的交换。就因为多了一个“引用(&)”。而fun2中是开辟的临时指针变量
*明白引用就能明白这里的效果。
*/
void fun7(int *&a,int *&b)
{
int *tem;
tem=a;
a=b;
b=tem;
cout<<"fun7(int *&a,int *&b):*a="<<*a<<",*b="<<*b<<endl;
}
/*这里达到的效果同fun3,二者一定程度上可以互相替换,只不过调用时有些区别!
*/
void fun8(int *&a,int *&b)
{
int tem;
tem=*a;
*a=*b;
*b=tem;
cout<<"fun8(int *&a,int *&b):*a="<<*a<<",*b="<<*b<<endl;
}
int main()
{
int x=13,*x0=&x,&x1=x;
int y=250,*y0=&y,&y1=y;
cout<<"\n调用前main():x="<<x<<",y="<<y<<endl;
fun1(x,y);
cout<<"调用后main():x="<<x<<",y="<<y<<endl;
//fun1(&x,&y);//错误
cout<<"\n调用前main():*x0="<<*x0<<",*y0="<<*y0<<endl;
fun1(*x0,*y0);//这与上面的fun1调用没有区别
cout<<"调用后main():*x0="<<*x0<<",*y0="<<*y0<<endl;
cout<<"\n调用前main():*x0="<<*x0<<",*y0="<<*y0<<endl;
fun2(x0,y0);//把指针的地址传递过去,
cout<<"调用后main():*x0="<<*x0<<",*y0="<<*y0<<endl;
cout<<"\n调用前main():x="<<x<<",y="<<y<<endl;
fun2(&x,&y);//把指针的地址的副本传递过去(按值传递),依旧不会影响原来的指针x0y0的指向
cout<<"调用后main():x="<<x<<",y="<<y<<endl;
cout<<"\n调用前main():*x0="<<*x0<<",*y0="<<*y0<<endl;
fun3(x0,y0);
cout<<"调用后main():*x0="<<*x0<<",*y0="<<*y0<<endl;
cout<<"调用后main():x="<<x<<",y="<<y<<endl;
cout<<"\n调用前main():x="<<x<<",y="<<y<<endl;
fun3(&x,&y);
cout<<"调用后main():x="<<x<<",y="<<y<<endl;
cout<<"调用后main():*x0="<<*x0<<",*y0="<<*y0<<endl;
cout<<"\n调用前main():x="<<x<<",y="<<y<<endl;
fun4(x,y);
cout<<"调用后main():x="<<x<<",y="<<y<<endl;
cout<<"\n调用前main():*x0="<<*x0<<",*y0="<<*y0<<endl;
fun4(*x0,*y0);
cout<<"调用后main():*x0="<<*x0<<",*y0="<<*y0<<endl;
//fun5(&x,&y);//错误
cout<<"\n调用前main():x="<<x<<",y="<<y<<endl;
fun5(&x0,&y0);
cout<<"调用后main():x="<<x<<",y="<<y<<endl;
cout<<"调用后main():*x0="<<*x0<<",*y0="<<*y0<<endl;
cout<<"\n调用前main():*x0="<<*x0<<",*y0="<<*y0<<endl;
fun6(&x0,&y0);
cout<<"调用后main():*x0="<<*x0<<",*y0="<<*y0<<endl;
cout<<"调用后main():x="<<x<<",y="<<y<<endl;
//这里之所以把fun8调用放在fun7之前,是因为如果fun7在fun8前,那么fun7调用后x0指向y,y0指向x,
//再调用fun8得到的结果不便于理解。
cout<<"\n调用前main():*x0="<<*x0<<",*y0="<<*y0<<endl;
fun8(x0,y0);
cout<<"调用后main():*x0="<<*x0<<",*y0="<<*y0<<endl;
cout<<"调用后main():x="<<x<<",y="<<y<<endl;
cout<<"\n调用前main():*x0="<<*x0<<",*y0="<<*y0<<endl;
fun7(x0,y0);
cout<<"调用后main():*x0="<<*x0<<",*y0="<<*y0<<endl;
cout<<"调用后main():x="<<x<<",y="<<y<<endl;
//fun7(&x,&y);//错误
system("pause");
return 0;
}
[解决办法]
我拍手~~~~~~~~~
[解决办法]
一起拍
[解决办法]
此贴必顶
[解决办法]
楼主真是有心人,总结的很好!
谢谢分享!
[解决办法]
好,
还有
const 和非cosnt参数
const 在类型前后,在函数名前后的区别也可以总结一下
[解决办法]
很少用指向指针的指针,学习一下。
[解决办法]
支持楼主,好厉害啊
[解决办法]
我觉得楼主所说的那些,只要理解了变量的左值和右值,特别是指针的左值和右值,对于函数的参数是传值的就能够理解清楚了。
一个变量有两个值,该变量的地址为左值,即地址值,变量的数据是其数据值,即为右值。在C中,函数的参数是只将实参的右值传入函数体内。相当于在函数内部定义了与实参名一模一样的临时变量,并且将实参的数据值赋给这个定义的临时变量。在函数内部所有对该实参的操作,实际上操作的是这种定义的临时变量。
而指针变量的右值,也就是数据值,也是一个地址。所以在函数内部,可以对实参的右值进行操作,但无法操作实参的左值。
在C++中,有了引用,之所以叫引用,是因为为不为引用变量另外开辟变量空间,而是让该变量与被引用的变量使用相同的地址,所以引用变量的右值肯定时刻与被引用的变量值保持一致。如果函数的参数定义为引用的话,即使在函数内部,操作引用变量时,由于其左值与实参的左值值是相同的,所以更改引用变量的数据,就是更改被引用变量的数据。
------解决方案--------------------

正在研究函数
[解决办法]

[解决办法]
很好很强大!