为什么函数参数要用&符号?——C++引用传递的秘密¶
你有没有遇到过这样的情况:写一个函数想修改某个变量,结果发现修改后变量的值没变化?或者处理一个很大的结构体,每次调用函数都要“复制”一份,既慢又占内存?这时候,C++的引用传递就能派上用场了,而&符号就是它的“开关”。今天我们就来拆解一下,为什么函数参数需要用&,以及它到底是怎么工作的。
先说说“值传递”的烦恼¶
在C++中,默认情况下函数参数是值传递的。什么意思呢?就是函数接收的是实参的“副本”,而不是实参本身。比如下面这个交换两个数的函数:
void swap(int a, int b) {
int temp = a;
a = b;
b = temp;
}
int main() {
int x = 10, y = 20;
swap(x, y);
cout << "交换后:x=" << x << ", y=" << y; // 这里输出的还是x=10, y=20
return 0;
}
为什么没交换成功?因为swap函数里的a和b是x和y的“副本”。修改a和b,只是修改了副本,原变量x和y根本没动。这就是值传递的局限:如果要修改外部变量,值传递做不到。
什么是“引用”?¶
“引用”(Reference)是C++的一个特性,它本质上是变量的别名。可以理解为给原变量取了个“外号”,这个“外号”和原变量指向同一块内存空间。比如:
int a = 10;
int &b = a; // b是a的引用,现在b和a指向同一块内存
b = 20; // 修改b,实际上是修改了a
cout << a; // 输出20(a也跟着变了)
这时候,如果把引用作为函数参数,会发生什么?
引用传递:用&让函数“直接修改”外部变量¶
当函数参数用&声明时,这个参数就是原变量的引用。这样,函数里对参数的修改,就相当于直接修改了原变量。我们把刚才的swap函数改成引用传递:
void swap(int &a, int &b) { // 参数前加&,表示引用传递
int temp = a;
a = b;
b = temp;
}
int main() {
int x = 10, y = 20;
swap(x, y); // 直接传x和y,不用传地址
cout << "交换后:x=" << x << ", y=" << y; // 输出x=20, y=10(成功修改!)
return 0;
}
关键点:&在这里是“引用声明符”,不是“取地址运算符”。当你写int &a时,a就成了外部变量的引用,后续对a的操作都会影响原变量。
引用传递的“好处”¶
- 直接修改外部变量:不用像值传递那样只能修改副本,能直接改实参。
- 避免大对象“拷贝浪费”:如果参数是一个很大的结构体或数组,值传递会复制整个对象(浪费时间和内存),而引用传递只传递一个“别名”,效率极高。比如处理一个10000个元素的数组,引用传递比值传递快得多。
- 代码更简洁:比用指针传递参数更直观(后面会对比指针)。
别搞混!&的两种身份¶
&在C++里有两个常见身份,别搞混了:
- 取地址运算符:&var表示“取变量var的地址”,返回的是指针类型(比如int *)。
- 引用声明符:int &a表示“声明a是int类型的引用”,必须在声明时初始化(不能是nullptr)。
举个对比:
// 引用参数(&是声明符)
void func1(int &a) { a = 100; }
// 指针参数(&是取地址运算符)
void func2(int *a) { *a = 100; } // 用指针要解引用*a
int main() {
int x = 10;
func1(x); // 直接传x,引用参数修改x
func2(&x); // 传x的地址,指针参数修改x
return 0;
}
- 函数
func1的参数是引用,调用时直接传x; - 函数
func2的参数是指针,调用时需要传&x(x的地址)。
引用的“注意事项”¶
- 必须初始化:引用声明时必须绑定一个变量,不能写成
int &a;(这样会报错),必须像int &a = x;这样。 - 不能“空引用”:引用不能指向
nullptr,也不能被赋值为0(指针可以)。 - 一旦绑定,不能改变指向:引用声明后,永远指向同一个变量,不像指针可以随时换目标。
总结:什么时候用引用传递?¶
- 当需要修改外部变量时(值传递做不到);
- 当处理大对象(结构体、数组等)时,避免拷贝浪费;
- 当需要简化代码,用引用比用指针更直观时。
记住,函数参数前加&就是“引用声明符”,它让函数能直接操作外部变量,而不用依赖复杂的指针解引用。下次写函数时,如果发现值传递“改不动”变量,试试给参数加上&,让函数成为“变量的管家”吧!