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);看看按照上述理解的结果是否正确。
- c语言参数传递问题
- java/c/c++/c#参数传递问题
- C语言函数参数传递问题
- C语言多维数组参数传递问题
- 关于C#中的参数传递问题
- 关于C语言传递参数的问题
- C/C++--参数传递
- C#中的参数传递
- C#中的参数传递
- C#中的参数传递
- C#中的参数传递
- C#参数传递
- c语言参数传递
- C语言参数传递
- c#--参数传递
- C参数传递
- C语言参数传递
- C语言参数传递
- 博弈论基础
- The Twelve-Factor App
- leetcode: LRU Cache
- thingking in Java 通过异常处理错误
- 【转载】linux系统的负载与CPU、内存、硬盘、用户数监控shell脚本
- C++参数传递问题
- POJ 3415Common Substrings 后缀数组 + 线段树 + dfs
- cocos2dx3.x加载使用cocostudio导出的UI项目
- 文件存储
- 并查集II
- HDU1016 Prime Ring Problem(深度优先搜索)
- Eclipse快捷键
- UNIX C 链表实现族谱图
- 有一个二叉树,现在怀疑它有一个结点有2个父节点,请写出一个函数来判断该二叉树是否存在一个节点含有2个父节点。如果存在,返回true,否则返回false。