值传递:
形参是实参的拷贝,改变形参的值并不会影响外部实参的值。从被调用函数的角度来说,值传递是单向的(实参->形参),参数的值只能传入,不能传出。当函数内部需要修改参数,并且不希望这个改变影响调用者时,采用值传递。
指针传递:
形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作
引用传递:
形参相当于是实参的“别名”,对形参的操作其实就是对实参的操作,在引用传递过程中,被调函数的形式参数虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。
在很多年前刚学编程时,一开始我也觉得这样的话很confusing。不过其实可以更简单的理解:函数都是传值的。这句话的意思是,形参获得的都是实参的值,比如你传入一个引用foo(&a)
,形参将获得这个引用的“值”(地址,而不是指地址中的值)。所以直接对这个引用进行操作,当然会改变其地址中的值了。
讲个例子。先看一下这一段程序:
#include
using namespace std;
void fun(int *p) {
int q = 10;
p = &q;
}
int main() {
int r = 20;
int p = &r;
fun(p);
cout<<p<<endl;
return 0;
}
输出是多少呢?跑一下回发现是20。原因很简单,函数传值,形参的值改变不影响实参的值。所以在fun里面,p的值变成了临时变量q的地址,但是不影响main中p的值。
如果把fun改成这样呢?
void fun(int *p) {
*p = *p + 1;
}
输出变成了21,这是因为我们通过p的地址改变了该地址的内容。
那如果fun改成这样呢?
void fun(int *p) {
int q = 10;
p = &q;
*p = *p + 1;
}
输出还是20.因为在fun中,局部变量p的值已经变成了q的地址,所以*p = *p + 1;
改变的是q的值而非main中r的值。