例子1:
int main()
{
/* 引用基本使用
作用:给变量起别名
语法:数据类型 &别名 = 原名
*/
int a = 10;
int b = 20;
//int &c //错误,引用必须初始化
int& c = a; //一旦初始化后,就不可以更改
c = b; //赋值操作,非更改引用,此时修改了c,则a同时改变
//注:输出 a、b、c 值都为20
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl;
system("pause");
return 0;
}
例子2:
int main()
{
int a = 3;
int& b = a;
int c = a;
cout << "a:" << a << endl;
cout << "b:" << b << endl;
cout << "c:" << c << endl;
b = 10;
cout << "a:" << a << endl;
cout << "b:" << b << endl;
cout << "c:" << c << endl;
cout << "&a:" << &a << endl;
cout << "&b:" << &b << endl;
cout << "&c:" << &c << endl;
system("pause");
return 0;
}
输出:
a:3
b:3
c:3
a:10
b:10
c:3
&a:00000026644FF864
&b:00000026644FF864
&c:00000026644FF8A4
//可以看出a和b的地址相同
例子3:
#include <iostream>
using namespace std;
//1.值传递
void swapA(int a, int b)
{
int tmp = a;
a = b;
b = tmp;
}
//2.地址传递
void swapB(int* value1, int* value2)
{
int tmp = *value1;
*value1 = *value2;
*value2 = tmp;
}
//3.引用传递
void swapC(int& a, int& b)
{
int tmp = a;
a = b;
b = tmp;
}
int main()
{
int a = 10;
int b = 20;
//swapA(a,b); //值传递,形参不会修饰实参
//swapB(&a,&b); //地址传递,形参会修饰实参
swapC(a, b); //引用传递,形参会修饰实参
cout << "a=" << a << ", b=" << b << endl;
system("pause");
return 0;
}
值传递:
这个比较简单,实参a 原本指向地址 1638212,代表1638212这个地址的值是10。在swapA函数中,实参a将值拷贝给形参a,形参a此时也在内存中拥有另外一个地址,地址= xxxx,值为10,在所有的函数体内的操作,都是对 xxxx这个地址的操作,所以并不会影响实际参数的值。
地址传递:
在这里我们习惯把指针写成int* a,int* b而不是int *a,int *b。我们可以这样理解:指针是一种特殊的数据类型,若 int c = 5;int* a = &c;则a是一个指针变量,它的值是c的地址!星号“*”是一个取值操作,和号“&”是一个取址操作。
由于函数传入的是地址,而函数体内又对地址进行取值和赋值操作,所以相对应的地址的值发生了改变。但是地址并没有实际改变,从函数的输出来看,a的地址并不会改变。在C语言中,函数在运行的时候会对每个变量分配内存地址,分配之后只要变量不被销毁,这个地址不能改变。&a = &b;是无法编译通过的。
引用传递:
引用是变量的一个别名,调用这个别名和调用这个变量是完全一样的。所以swapC的结果可以解释。值得注意的是,由于引用时别名,所以引用并不是一种数据类型,内存并不会给它单独分配内存,而是直接调用它所引用的变量。这个与地址传递也就是指针是不一样的(也就是说一个指针虽然指向一个变量,但是这个指针变量在内存中是有地址分配的)
就是说,引用的这个别名,没有重新分配地址(和值传递的重要区别),所以对别名修改,就是对待交换的值修改。