close

何為傳值call by value、傳址call by address、傳參考call by reference?

『也可以叫做pass by value、pass by address、pass by reference』

傳址call by address傳說中是台灣人發明的講法,

其實傳址它本質上也是call by value,或者是call by value of pointer,至於為什麼晚點再說明

傳值call by value:

 

swap意思是交換,所以這段程式碼很明顯的就是想交換主程式a跟b的值,

如果你連上面的程式碼都搞不清楚,可能得先建議你去網路或者看書學一些基本的概念。

在這段程式碼中,我們在主程式宣告了a跟b的值,見下圖:

  main的a main的b      
儲存值 5 10 …… …… ……
記憶體位址 0×04 0×08 …… …… ……

PS:記憶體的位址應該會是像0x28ff44這種樣子,可是為了方便所以我把它縮短成如上所示

當程式執行第一行的宣告後,系統會立即分配記憶體空間給變數使用,且將儲存的值存到變數裡

接著當下一行我們呼叫了副程式swap(a,b),意思就是要把a跟b的引數給swap副程式c跟d使用

且是按照順序的給下去,swap第一個參數的c對應主程式第一個給的引數a

  main的a main的b   swap的c swap的d
儲存值 5 10 …… 5 10
記憶體位址 0×04 0×08 …… 0×16 0×20

當副程式的程式執行完之後記憶體會變如下:

  main的a main的b   swap的c swap的d
儲存值 5 10 …… 10 5
記憶體位址 0×04 0×08 …… 0×16 0×20

最後回到主程式並印出a跟b的值,會發現a跟b根本沒有改變,為什麼!?

這就是因為你使用的方式是傳值call by value,傳值的意思顧名思義就是只把『值』複製給對方

對方拿到了你的值以後做任何改變都不會影響到原本的值,因此如果你想要利用副程式把a跟b交換,可以使用傳址

傳址call by address:

在這段程式碼中,我們在主程式宣告了a跟b的值,同樣見下圖:

  main的a main的b      
儲存值 5 10 …… …… ……
記憶體位址 0×04 0×08 …… …… ……

接著當下一行我們呼叫了副程式swap(&a,&b),意思就是要把a跟b的位址給swap副程式c跟d使用

&的意思就是要領出該變數的『位址』,因此&a的話是把0×04的記憶體位址給對方

而副程式的swap(int *c , int *d)

其中*的意思是『指標Pointer』指標是用來儲存記憶體位址的,

因此這段程式的意思就是『指標c指向a』執行到副程式後記憶體如下表示:

  main的a main的b   swap的*c swap的*d
儲存值 5 10 …… 0×04 0×08
記憶體位址 0×04 0×08 …… 0×16 0×20

如果你在副程式裡直接執行printf(“%d”,c); 印出來的內容只會是主程式a的記憶體位置,也就是0×04

所以當你想用c來印出a的內容,得用*c才可以印出printf(“%d”,*c);

在這邊*已經不是指標的意思,而是『提領Dereference』,簡單說就是提取本身所指向的位址的值,也就是a的值5

所以副程式執行完交換後記憶體如下表示:

  main的a main的b   swap的*c swap的*d
儲存值 10 5 …… 0×04 0×08
記憶體位址 0×04 0×08 …… 0×16 0×20

所以副程式執行完後,主程式的printf函式就可以順利的印出交換後的a與b。

看到這裡很多人應該都會認為這樣的確是call by address不是嗎?畢竟傳過去的是位址,而不是值

這邊有一段程式碼給大家看看:

當第一個printf執行後,印出來的c跟d都是5

可是下一行的d=&b執行後在印一次,c卻仍然是5,d卻變成了10

因此你可以這樣想:傳指標,仍然也是call by value,只是那個value是指標本身,

複製的內容也是指標本身,只不過那個值Value剛好就是位址address

所以各位要大概瞭解call by address本質上也是call by value或者叫call by value of pointer

不過畢竟這call by address的講法已經在台灣紮根了,所以也不用強硬的堅持C語言只有call by value

總結:

指標是專門用來儲存記憶體的位址,但指標本身也有自己的記憶體位址

int *ptr;     這裡的*號代表指標Pointer,在未指向任何位址的指標,你不可以去提領他,這是非法行為
int *ptr2=NULL    如果指標宣告後一開始還沒打算讓他指向任何東西,良好習慣就是給他一個NULL值

int *ptr3 = &x;  &x意思是要把x的記憶體位址傳出來給指標ptr3
printf(“%d”,*ptr3);    這裡的*號代表提領Dereference,意思是要把本身指向的位址的值提領出來

傳參考call by reference:

傳參考是C++才有的東西,C語言是沒有的唷,可以說call by reference是call by address的進化版,

因為傳址的指標它的內容為指向的位址,但他本身仍然有記憶體位址,但是傳參考是不會有的

我們先來看程式碼

當主程式執行後記憶體如下

  main的a main的b      
儲存值 5 10 …… …… ……
記憶體位址 0×04 0×08 …… …… ……

在呼叫swap(a,b)時像平常一樣直接給引數就好,但副程式那邊必須要把c跟d加上&,變成void swap (int &c , int &d)

PS:有些人會長會被傳參考的&跟上面在講的傳址的&一樣,其實是不一樣的,別搞混

這樣就會是用傳參考的方式來接收主程式a跟b的值,此時記憶體如下所示:

  main的a main的b   swap的&c swap的&d
儲存值 5 10 …… 5 10
記憶體位址 0×04 0×08 …… 0×04 0×08

沒錯,傳參考的意思其實簡單來說就是變數的別名、綽號,因此c的記憶體位址跟主程式的a的位址一樣

因為一樣,所以c做任何改變a也會跟著改變,d改變b也會跟著改變

注意的是,一旦變數已經是別的變數的參考,就不可以再參考別的變數

===================

int a=5;
int &c;   //錯誤,傳參考必須在宣告的時候就一起給參考的對象,沒辦法之後再給。

====================================================================

C++的call by reference,其實才算是call by address,來看同樣是上面的例子

==========================

arrow
arrow
    文章標籤
    傳值、傳址、傳參考
    全站熱搜
    創作者介紹
    創作者 cout 的頭像
    cout

    火星上的c家家

    cout 發表在 痞客邦 留言(2) 人氣()