C++ 函数参数传递

值 传递

当初始化一个非引用类型的变量时,初始值被拷贝给变量。此时,对变量的改动不会影响初始值:

int n = 0;
int i = n;
u = 42; //i的值改变,n的值不会变

函数传值参数的机理完全一样。函数对形参做的所有操作都不会影响到实参。

指针 传递

拷贝的是指针的值,拷贝之后,两个指针是不同的指针。

void reset(int *ip){
    *ip = 0; //改变了指针ip所指对象的值
    ip = 0;  //只改变了ip的局部拷贝,实参未被改变
}

引用 传递

会议过去所学的知识,我们知道对于引用的操作实际上是作用在引用所引的对象上:

int n = 0, i = 42;
int &r = n;   //r绑定了n(即r是n的另一个名字)
r = 42;  //现在n的值是42
r = i;   //现在n的值和i相同
i = r;   //现在i的值和n相同

和其他引用一样,引用形参绑定了初始化它的对象。通过使用引用形参,允许函数改变一个或多个实参的值。所以可以使用引用避免拷贝,使用引用形参返回额外的信息。

void reset(int &i){
    i = 0;  //改了i所引对象的值
}

emmm?

形参相当于是实参的“别名”,对形参的操作其实就是对实参的操作,在引用传递过程中,被调函数的形式参数虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。

这里写图片描述

我抄的:

int a = 10;

int & r = a;

cout << &a << endl;

cout << &r << endl;

从上面的例子当中可以看出:它们得出的结果是相同的,这时便会有人说,r和a所占用的内存空间是相同的,因为打印出来的地址是相同的。所以这些教材上对于引用变量的操作,称之为声明一个引用变量,而非定义。因为教材的编写者认为引用变量并不占用空间。

但是,如果你使用调试器调试一下,看一下汇编的代码,就会产生新的迷惑了。

00401040 push ebp
00401041 mov ebp,esp
00401043 sub esp,48h
00401046 push ebx
00401047 push esi
00401048 push edi
00401049 lea edi,[ebp-48h]
0040104C mov ecx,12h
00401051 mov eax,0CCCCCCCCh
00401056 rep stos dword ptr [edi]

5: int a = 10;
00401058 mov dword ptr [ebp-4],0Ah
6: int & r = a;
0040105F lea eax,[ebp-4]
00401062 mov dword ptr [ebp-8],eax

从这段汇编代码来看,r和a的空间并不相同,那这又怎么解释呢?

基于此,我得出了一个非常合理的解释:

如果定义(我认为引用变量占用空间,故称之为定义)一个引用变量,这个时候引用变量实际上在内存中已经申请了一个空间,是4个字节的(32bit系统中),它本身和指针是相同的。也就是说引用和指针对于编译器本身来说操作是相同的,只是对于用户来说操作不同而已。

猜你喜欢

转载自blog.csdn.net/love_wanling/article/details/78169304