C++参数传递问题

来源:互联网 发布:北京java培训哪家好 编辑:程序博客网 时间:2024/05/22 05:31

偶然碰到一个十分奇怪的问题,如下的代码段。

#include <iostream>using namespace std;void fun(int a,int b,int c,int d);void main(){int i=6;fun(++i,i++,i++,++i);cout<<i;while(1);}void fun(int a,int b,int c,int d){cout<<a<<endl;cout<<b<<endl;cout<<c<<endl;cout<<d<<endl;}
大家在编译器上跑下结果,我的结果是这样的:10 8 7 10 10。(第五个10是main输出的i)

大家可以自己想思考下这样结果的原因。


想了很久,查询了很多资料,最后我的理解如下,如果有什么不妥大家一起讨论学习一下。


首先、main函数执行到fun函数时,先计算函数的实参,这顺序一般函数都是从右至左,编译器需要从右至左存储参数,所以等于是执行了++i,i++,i++,++i这四步。

我们知道在内存模块中,有一个堆栈块,用于存储局部变量,形参,实参。在这个代码中,函数参数使用值传递,也就将实参的值赋给了形参。而在堆栈块中,实参和形参是分开存储的,所以在main中调用fun函数时,会开辟一块内存用于保存形参,然后将实参值赋值过来。

然后,还有一个要注意的地方,自增自减操作符,首先,前置自增是操作数加一,同时操作结果是修改后的值;而后置自增是操作数加一,但操作结果是修改前的值。比如

int i=0;int j;j=++i;//结果是j=1,i=1j=i++;//结果是j=1,i=2

更重要的是,前置操作返回的是一个左值,而后置操作返回的是一个右值。左值可直接作为实参,而右值一般是不能直接作为参数传递的,但是现在的c++版本中,提供了一个右值引用,所以现在右值也可以当实参,不过是引用传递而不是值传递。(大家对值传递与引用传递的区别一定比较熟悉了)

综合上述,我理解的过程是这样,首先执行到fun入口,main函数先计算实参,首先是++i,这相当于直接在代码中加了一句++i,直接作为左值,而这修改的是i本身(这时i为7),再将这个i作为参数(所以后面对i修改,这里参数的值也会变);然后是i++,不能直接做实参,所以会开辟一块新内存,保存i++的返回值为7(这时i为8);之后又是i++,同理,开辟一块新内存,保存i++的返回值为8(这时i为9);最后是++i,相当与直接修改了i(这时i为10)。

然后执行到fun函数,按照上面相反的顺序来取形参,参数a直接赋予i的最新结果10;参数b为上面第二次开辟内存的引用,结果是8;参数c为上面第一次开辟内存的引用,结果是7;而参数d是直接赋予i的最新值10。

大家可以试着改变mian中fun函数的实参列表,如fun(i++,++i,i,i++,++i);看看按照上述理解的结果是否正确。



0 0