爲什麼函數參數要用&符號?——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(指針可以)。 - 一旦綁定,不能改變指向:引用聲明後,永遠指向同一個變量,不像指針可以隨時換目標。
總結:什麼時候用引用傳遞?¶
- 當需要修改外部變量時(值傳遞做不到);
- 當處理大對象(結構體、數組等)時,避免拷貝浪費;
- 當需要簡化代碼,用引用比用指針更直觀時。
記住,函數參數前加&就是“引用聲明符”,它讓函數能直接操作外部變量,而不用依賴複雜的指針解引用。下次寫函數時,如果發現值傳遞“改不動”變量,試試給參數加上&,讓函數成爲“變量的管家”吧!