[C/C++] 指標教學[四]: Pass by value vs Pass by reference

MuLong PuYang
9 min readJul 19, 2019

當我們在寫程式的時候,遇到函數的參數傳遞,常常使用到 Pass by value (或叫 Call by value) 或者是 Pass by reference (或叫 Call by reference),這邊網誌來介紹這兩種觀念

首先,我們先來釐清這兩大觀念再來細部介紹,關於 Pass by value 與 Pass by reference,我覺得這一篇 stackoverflow 的文章其實講的滿好的: What’s the difference between passing by reference vs. passing by value? ,這裡我擷取前面一部分翻譯成中文。

  • When a parameter is passed by reference, the caller and the callee use the same variable for the parameter. If the callee modifies the parameter variable, the effect is visible to the caller’s variable.
  • 當一個參數是 pass by reference,對於參數而言,呼叫與被呼叫者,都使用相同的變數。如果被呼叫者改變了參數的數值,同樣的影響會影響到呼叫者的變數。
  • When a parameter is passed by value, the caller and callee have two independent variables with the same value. If the callee modifies the parameter variable, the effect is not visible to the caller.
  • 當一個參數是 pass by value,呼叫者與被呼叫者是兩個獨立的變數但使用相同的數值。如果被呼叫者更改了參數的數值,並不會影響到呼叫者本身。

所以我們可以看到,事實上 pass by reference 與 pass by value 最大的不同就是當變數傳遞進去之後,函數中的區域變數與船進去的變數之間是否有連動,pass by reference 在函數中更改,則原本傳遞進去的變數也會做相對應的更改,因為兩者其實是相等的,只是名子是不一樣的。而所謂的 pass by value 就是非常純粹的只把值傳進去,函數裡的變數與傳遞進去的變數之間沒有關係,更改了函數裡面的變數的話,也不會影響到傳遞進去的變數。

Pass by value

這裡我們寫一個程式,首先我們先宣告一個 int num1 並賦值為 2,並另外宣告一個函數 setNum(),這個函數有一個參數 num2,進入這個函數後,函數會把 num2 設為 5,這時候我們再跳回主函數的時候,來看看 num1 是否會被改變

#include <stdio.h>void setNum(int num2);int main(int argc, char* argv[])
{
int num1 = 2;
printf("before setNum(), num1: %d\n", num1);

setNum(num1);
printf("after setNum(), num1: %d\n", num1);}void setNum(int num2)
{
printf("before setting, num2: %d\n", num2);
num2 = 5;printf("after sett ing, num2: %d\n", num2);
}

執行結果

before setNum(), num1: 2
before setting, num2: 2
after setting, num2: 5
after setNum(), num1: 2

我們可以看到參數傳進去函數後,也無法更改 num1 的數值。

如果我們用圖片解釋的話我們可以假設 num1的位址為0x000000aa,而數值是 2 ,num2的位址是0x000000ba,數值被更改為 5,但不會對 num1 造成影響。

那我們可以使用 pass by value 的方式,使 num1與 num2 連動,答案是可以的,只是以下的方式常常被誤解為 pass by reference。

Pointer方式的pass by value,使傳遞參數與接收參數之間彼此連動

我們可以使用 pointer 的 pass by value 的方式,使參數之間彼此連動,而不靠 pass by reference,而事實上,我們使用 C 語言的時候,也沒有辦法使用 reference,所以也只有使用這個方法來同時改變傳進來參數的數值。

這一篇 c語言有沒有call by reference(or call by address) ? 裡面有清楚的提到其實 C 語言並沒有 pass by reference

這篇文章的作者有先提到

原始的C語言發明人K&R 在其原著 “The C programming language” 中即已說明, C語言只有call by value, 這點不須爭論.

另外這篇的網誌也有提到在這個網頁: https://clc-wiki.net/wiki/C_language:Terms:Pass_by_reference 有清楚的描述到如下這段話

C does not directly support pass by reference because it always uses pass by value, but a programmer can implement pass by reference by passing a pointer to the variable that the programmer wants passed by reference.

這裡我把它翻譯成中文

C 不直接支持 pass by reference 因為它總使用 pass by value,但是一個程式設計師可以實作 pass by reference 藉由傳遞指標到程式設計師希望 pass by reference 的變數。

總而言之,就是使用 pointer 的方法,來達成 pass by reference 的效果

這次我們把 setNum 裡的參數改成 int *num 的指標形式,接著在傳入的時候我們使用 setNum(&num1) 傳入,看經過這個函數之後,num1 的數值是否會被更改。

#include <stdio.h>void setNum(int *num2);int main(int argc, char* argv[])
{
int num1 = 2;
printf("before setNum(), num1: %d\n", num1);

setNum(&num1);
printf("after setNum(), num1: %d\n", num1);}void setNum(int *num2)
{
printf("before setting, num2: %d\n", *num2);
*num2 = 5;printf("after setting, num2: %d\n", *num2);
}

輸出結果

before setNum(), num1: 2
before setting, num2: 2
after setting, num2: 5
after setNum(), num1: 5

可以看出 num1的數值最後改成了 5

這裡我們用圖片解釋的話,可以看成說 num2 是個指標變數,它的位址是0x000000ba,它指向了 num1,所以我們更改了*num2 的數值,num1理所當然地也會跟著改變。

Pass by reference

最後就是 Pass by reference,Pass by reference 是 C++有的而 C語言並沒有,我們在變數前面添加 & 變成 reference type,所以在這裡,我們對setNum 的參數形式寫成這樣 int &num2。

#include <stdio.h>void setNum(int &num2);int main(int argc, char* argv[])
{
int num1 = 2;
printf("before setNum(), num1: %d\n", num1);

setNum(num1);
printf("after setNum(), num1: %d\n", num1);}void setNum(int &num2)
{
printf("before setting, num2: %d\n", num2);
num2 = 5;printf("after setting, num2: %d\n", num2);
}

輸出結果

我們發現我們在函數中更改 num2 為 5,而原本的 num1 數值也同樣被更改,Pass by reference 會讓呼叫者與被呼叫者的變數是相同的。

before setNum(), num1: 2
before setting, num2: 2
after setting, num2: 5
after setNum(), num1: 5

這裡我們用圖解釋的話,就是 num1與num2為同樣的變數,只是名稱不一樣,所以更改了num2,num1的數值就一定會被改變

參考資料:

What’s the difference between passing by reference vs. passing by value?

維基百科的參照中文條目

c語言有沒有call by reference(or call by address) ?

參數的傳值、傳參考

什麼是傳值call by value、傳址call by address、傳參考call by reference

c++ — 什麼是「參照」- reference

--

--