C/C 的按值传递和按地址传递有明显不同,下面对他们作个区别:
按值传递:在调用函数中将原函数的值拷贝一份过去被调用的函数,在被调用函数中对该值的修改不会影响原函数的值。
按地址传递:在调用函数的时候将原函数的值所在的地址拷贝一份过去,被调用函数对这个地址所作的修改会影响原来的值。
鉴于本人表达能力有限,这样说可能有点迷惑,下面直接上图:
一、按值传递
代码语言:javascript复制 #include<iostream>
using
namespace std;
void changeNumber(int x);
int main(void)
{
int a =
10;
cout <<
"a = " << a << endl;
changeNumber(a);
cout <<
"Now a = " << a << endl;
return
0;
}
void changeNumber(int x)
{
x = x
5;
}
这里是一个十分简单的程序,其中包含了一个changeNumber()函数,意图是改变在main()函数中变量 a 的值,显而易见,这是一种按值传递,changeNumber()函数不可能完成任务:
可以看到,a并没有被改变。原因很简单,按值传递,当调用changeNumber()函数的时候,以 a 作为实际参数,在程序跳到changeNumber()函数的时候,会拷贝一份a的数据,也就是说,在内存空间中重新开辟了一块空间,它的作用就是用来存储a的值,并且这块空间的名称为 x,也就是changeNumber()中的这个x,注意,这个x所在的空间和a所在的空间是完全不同的两块内存(通过对他们分别输出地址可以得出),既然他们根本不属于同个地方,那么对x所作的任何修改都无法影响a。
二、按地址传递
如果这么写代码:
代码语言:javascript复制 #include<iostream>
using
namespace std;
void changeNumber(int* x);
int main(void)
{
int a =
10;
cout <<
"a = " << a << endl;
changeNumber(&a);
cout <<
"Now a = " << a << endl;
return
0;
}
void changeNumber(int* x)
{
*x = *x
5;
}
这里的代码就是按地址传递,首先在changeNumber()的声明中,使用了int*类型而不是int类型,其次在main()函数调用changeNumber()函数的时候使用的实参是&a而不是a,这就传递了一个地址给changeNumber()函数,这个changeNumber()就可以完成修改a的任务:
按照我的理解,按地址传递实际上是一种特殊的按值传递,原因如下:
1.main()函数调用changeNumber()的时候,将a的地址,也就是&a传递给changeNumber()函数,这实际上就是将a的地址拷贝一份过去给changeNumber()函数,在前面的例子中,main()拷贝并传递的是a,这里main()拷贝并传递的是&a,两者都可以理解为按值传递,只不过第二个例子中的“值”是a的地址而已
2.changeNumber()函数被调用之后,它根据传过来的地址值(请注意,这里说的是地址值,因为地址本身也是一个可见的数值),在内存中开辟一块新的空间,这块空间是用来存储这个地址值的,换句话说,这块空间上的内容就是a的地址,这似乎有点难以理解,但事实就是这样的,然后使用 * 运算符对x进行操作,*x操作的就是a的具体的值,而x作为一个指针,它存有a的地址(或者说它指向a的地址),那么对*x所做的任何操作都会影响a的值。
拓展:
对于第二个例子,如果使用cout输出x,结果得到的将会是一个地址,并且这个地址与a的相同,这符合我前面所叙述的内容。
代码语言:javascript复制 #include<iostream>
using
namespace std;
void changeNumber(int* x);
int main(void)
{
int a =
10;
cout <<
"a = " << a << endl;
changeNumber(&a);
cout <<
"Now a = " << a << endl;
cout <<
"&a = " << &a << endl;
return
0;
}
void changeNumber(int* x)
{
*x = *x
5;
cout <<
"x = " << x << endl;
}
好,现在把注意点集中到这行代码上:
代码语言:javascript复制cout << "&x = " << &x << endl;
对这个&x进行输出,结果得到的又是另一个地址,事实上,这个地址就是调用changeNumber()函数时分配的内存空间,这块内存空间存储的便是x也是a的地址,当函数结束后,这块空间会被收回,上面的x的内容也会消失。
前面说了x存放的是a的地址,也就是说,x指向a的地址,如果有操作:
代码语言:javascript复制x = x 5
把这行代码添加到changeNumber()函数的最前面,即:
代码语言:javascript复制
代码语言:javascript复制 void changeNumber(int* x)
{
x = x
5;
*x = *x
5;
cout <<
"x = " << x << endl;
}
这样会发生的事情是:这个函数又无法完成修改main中a的值了,原因就是,x存放的不再是a的地址,x的值已经发生了移动,换句话说,x指向了别的地址。
由于C和C 语法的相似性,经过C环境下写出的代码,同样符合这个逻辑
之所以写这个东西,是因为看到有博主写了关于Java按值传递和按引用传递的文章,链接:
https://blog.csdn.net/javazejian/article/details/51192130
刚好最近在学Java,文章所述Java的按值传递和按引用传递使我对C 按值传递和按地址传递的理解产生了疑问,一番实验之后终于弄清楚了。原文章写的非常不错,建议同样正在学习Java的同学可以看一看。