在這篇文章,將會提到程式的函式在傳遞參數(shù)時的各種方式,之所以想寫這篇文章,是因?yàn)榘l(fā)現(xiàn)上程設(shè)助教課的時候聽助教講這個聽得很頭痛,然後也發(fā)現(xiàn)身邊初學(xué)程式的同學(xué)好像對這個也沒什麼概念,所以想來稍微分享一下我的想法。
- 傳值 (Call by value / Pass by value)
#include <iostream> using namespace std; int add(int a, int b){ return a + b; } int main(){ int a = 5; int b = 15; cout << add(a, b); // 輸出: 20 } |
照理來說,有學(xué)過函式概念的人,對傳值的觀念應(yīng)該已不陌生,所以我只會大略的講過去。當(dāng)我們傳入 a 和 b 到 add 這個函式裡面時,在 add 這個函式裡面的 a 和 b 其實(shí)和 main 裡面的 a 跟 b 是不一樣的東西,但是他們的值是一樣的,換句話說,當(dāng)你以 Pass by value 的方式傳遞參數(shù)時,函式會生成新的變數(shù)來儲存?zhèn)鬟M(jìn)來的值。
這也代表說你沒辦法在這段函式執(zhí)行時修改main裡面的 a 和 b ,因此,待會會再介紹另外兩種方式來解決這種困境。
這種傳遞參數(shù)的方式在某些時候可能會消耗大量的記憶體,尤其當(dāng)你的參數(shù)是一個非常巨大的物件時,程式會複製出一份一樣巨大的物件,多少會影響一些效能。
- 傳址 (call by address / pass by address)
傳址,顧名思義,我們不直接傳遞參數(shù)了,我們改傳遞參數(shù)的位址,在函式中藉由取值符號 * 就可以直接操控原本的值了,我用幾行程式碼來簡單說明:
#include <iostream> using namespace std; void divideBy5(int* k){ *k = *k / 5; } int main(){ int a = 15; divideBy5(&a); cout << a; // 輸出: 3 return 0; } |
在這個例子中,我們傳遞了 a 的位址給指標(biāo)變數(shù) k ,所以 k 目前儲存了 a 的位址,藉由取值符號 *,我們可以直接把 a 位址變成 a 變數(shù),也就是說 *k 等於 a,而 a = a / 5; 那麼 a 就會變成 3 ,就是最後cout的結(jié)果。這樣我們就解決了傳值那邊提到的「無法修改main裡變數(shù)的窘境」。
基本上這種傳遞方式就是指標(biāo)的應(yīng)用,利用位址和變數(shù)的關(guān)係,來達(dá)到傳遞不同scope之間的變數(shù)。
有一點(diǎn)非常值得一提,當(dāng)我們傳遞 a 的位址到 devideBy5 時,實(shí)際上這個函式也生成了 k 這個變數(shù),拿來儲存 a 的位址,有沒有發(fā)現(xiàn)什麼?這不就是跟 Pass by value 是同一個概念嗎!是的,Pass by address 就只是 Pass by value 的特例而已,本質(zhì)上來說 Pass by address 就是 Pass by value,只是傳的值變成位址而已。
- 傳參(考) (Call by reference / Pass by reference)
在C++裡面,只要在宣告的時候在變數(shù)前面加上「&」,就代表這個變數(shù)是一個參考(剛學(xué)指標(biāo)的朋友,別把這個跟取址符搞混喔)。那什麼是參考,很簡單當(dāng)我們宣告了一個參考時,我們必須給它初始化,而初始化就是給它另一個變數(shù),此時,你宣告的參考等同於你給他的變數(shù),只是名字不一樣而已,下面有一個例子:
#include <bits/stdc++.h> using namespace std; int main(){ int a = 0; int &b = a; for(int i = 0; i < 10; ++i, ++a){ cout << a << " " << b << "\n"; } return 0; } /** 輸出結(jié)果: * 0 0 * 1 1 * 2 2 * 3 3 * 4 4 * 5 5 * 6 6 * 7 7 * 8 8 * 9 9 * **/ |
我宣告了一個參考叫做 b ,並且賦值為 a ,此時的 b 就等同於 a ,只是名字不同而已,為了證明他們相同,我在下方寫了一個 for 迴圈,每跑一次就把 a 加 1 ,你會發(fā)現(xiàn)我沒有對b做任何修改,但 a 和 b 卻同步修改了,這就是reference的概念。
因此我們便可以利用這個特性來傳遞函數(shù)的參數(shù),下面是兩個值swap的函式:
#include <bits/stdc++.h> using namespace std; void mySwap(int &x, int &y){ int temp; temp = x; x = y; y = temp; } int main(){ int a = 20, b = 11; mySwap(a, b); cout << "a = " << a << ", b = " << b; // 輸出: "a = 11, b = 20" return 0; } |
如果你用前面的 Pass by value 的話,這個函數(shù)等於沒意義,因?yàn)榻粨Q的根本是不同的東西,不過我們加上了參考的概念,這樣就可以成功的交換 a 和 b 了,只不過他們在 mySwap 這個函式裡面叫做 x 和 y 而已。