[禁止转载]
传值与传址(Pass by Value and Pass by Address)及指针是学C和C++比较头疼的问题,该博客是专门为博主女朋友写的。
先看一个经典例子:如何通过函数交换两个变量的值
首先写一个小程序如下:
void swap1(int a, int b)
// 参数是普通变量
{
int t;
t = a;
a = b;
b = t;
}
int main()
{
int x = 3;
int y = 5;
swap1(x, y);
cout << "After swap1: x=" << x << " y=" << y << endl;
return 0;
}
结果如下:
由图可知,虽然在函数里交换了值,但是实参x,y的值并没有改变,这是因为进入函数swap1时,形参a,b是拷贝实参的副本,形参拷贝了值、在函数里改变了值,但都不会影响实参值的变化。通常把这种情况叫做“传值”。
那如何切实改变x,y的值呢?需要用到指针。写一个小程序如下:
void swap2(int* a, int* b)
// 参数是指针
{
int t = *a;
*a = *b;
*b = t;
// 用了解指针符号*,所以以上操作相当于目的地址所存值的交换
}
int main()
{
int x = 3;
int y = 5;
int *ptx = &x;
int *pty = &y;
cout<< "*ptx=" << *ptx << " *pty=" << *pty << endl;
swap2(ptx, pty);
cout << "After swap2: *ptx=" << *ptx << " *pty=" << *pty << endl;
return 0;
}
结果如下:
可以看出值确实发生了交换,背后的原理是什么呢?
首先我们把传递的参数从普通变量换成了指针,指针与变量的区别是:指针可以知道两处内存存放的东西
- 指针本身a : 存的是指针a所指变量的地址
- 指针所指向地址*a : 存的是变量的值
已知形参拷贝的是副本,但指针的副本也和实参指针一样存着变量的地址值,通过访问这个地址,我们改变这个地址所存的东西,也就是变量的值。这样实参所指变量也会被改变,因此达到通过函数交换变量值的目的。
通常把这种情况叫做“传址”
上述代码中存在一个问题:通过修改目的地址所存变量的值来到达交换的目的。是不是有些繁琐?
为什么不直接交换两个指针的指向?
于是就有一下程序:
void swap3(int* a, int* b)
// 参数是指针
{
int *t;
t = a;
a = b;
b = t;
}
int main()
{
int x = 3;
int y = 5;
int *ptx = &x;
int *pty = &y;
cout<< "*ptx=" << *ptx << " *pty=" << *pty << endl;
swap3(ptx, pty);
cout << "After swap3: *ptx=" << *ptx << " *pty=" << *pty << endl;
return 0;
}
结果如下:
诶?居然没有调换成功。
其实还是那个道理,形参是实参的一个副本,改变形参的值是不会影响实参的,虽然这里参数仍然是指针,但这种情况也叫做“传值”。
所以想改变指针的指向,我们需要用 指向指针的指针 来解决
void swap4(int** a, int** b)
// 参数是指针的指针
{
int *t;
t= *a;
*a = *b;
*b = t;
}
int main()
{
int x = 3;
int y = 5;
int *ptx = &x;
int *pty = &y;
cout<< "*ptx=" << *ptx << " *pty=" << *pty << endl;
swap4(&ptx, &pty);
cout << "After swap4: *ptx=" << *ptx << " *pty=" << *pty << endl; // 此时swap1为传值,swap2为传址
return 0;
}
调换成功,道理不解自明,只是需要注意一下指针的指针的写法。
在引入“引用”机制后也可通过引用&解决