close

這是一個討論很久的名詞問題。

void f(int *x)
{
     printf("%d", *x);
}

int main()
{
    int y=10;
    f(&y);
    return 0;
}

上面的 f 裡面的到底是 call by value 還是 call by address?嗯,對初學者而言,現在解釋只會愈解釋愈亂,
但有這種說法目前還沒人打我槍過 ( 希望以後也不要 XD) 。

f 函式裡面的引數傳遞,是 call by pointer (或是 pass by pointer)。

----------------

在C\C++中,Call By Pointer是傳送參數常用的方式。我們有討論過,如果使用的是Call By Value,那麼OS會幫副函式的引數再配置新的記憶體空間。既然這樣的話,那麼就將主函數 a, b 變數的記憶體位址,而副函式再”依址取值”(這也是指標的功用,如果不熟的話請再看01_初學指標請進 – 指標與位址)進行swap的動作。使用方式請看以下部份的程式碼 

void swap(int *c, int *d){…..}
void main(){
    int a, b;
    swap(&a, &b);

&a 為取變數a位址值,再給副函數的指標 c 當初始值。你可以把它想成是 int *c = &a ,指標c的初始化。同理,b和 d 的關係也是這樣。現在我們來看以下的程式碼。

程式碼:

// ====================================
// FileName: CallByAddress.cpp
// Author  : Edison.Shih.
// Complier: VC 2008

#include <stdio.h>


// ====================================
void Swap_A(int *a, int *b)
{
        int c;
        printf("\n=== swap_A function initial ===\n");
        printf(" *a = %6d, *b = %6d\n",    *a, *b);
        printf("  a = %06X, b = %06X\n",    a,  b);
        c = *a;
        *a = *b;
        *b = c;
        printf("\n=== swap_A function swap end ===\n");
        printf(" *a = %6d, *b = %6d\n",    *a, *b);
        printf("  a = %06X, b = %06X\n",    a,  b);
}

// ====================================
int main(int argc, char **argv)
{
        int a=10;
        int b=5;

        printf("\n *=== before swap in main ===* \n");
        printf(" a = %6d, b = %6d\n",    a, b);
        printf("&a = %06X,&b = %06X\n", &a,&b);
        Swap_A(&a, &b);

        printf("\n *=== after swap in main ===* \n");
        printf("  a = %6d,  b = %6d\n",    a, b);
        printf(" &a = %06X, &b = %06X\n", &a,&b);

        return 0;
}

// ====================================

 執行結果:


 *=== before swap in main ===*
 a =     10, b =      5
&a = 12FF60,&b = 12FF54

=== swap_A function initial ===
 *a =     10, *b =      5
  a = 12FF60, b = 12FF54
 &a = 12FE7C,&b = 12FE80

=== swap_A function swap end ===
 *a =      5, *b =     10
  a = 12FF60, b = 12FF54
 &a = 12FE7C,&b = 12FE80

 *=== after swap in main ===*
  a =      5,  b =     10
 &a = 12FF60, &b = 12FF54

說明:

在Swap_A之前,記憶體配置圖如下

儲存值

5

10

 

……..

……..

……..

記憶體位址

12FF54

12FF60

……..

……..

……..

……..

 

主函b

主函a

 

 

 

 

 

在剛進入 Swap_A時,OS一樣將會再配置二個空間給副函式的指標a, b,分別接主函式的a, b 的位址值,記憶體配置圖如下

儲存值

5

10

 

……..

12FF60

12FF54

記憶體位址

12FF54

12FF60

……..

……..

12FF7C

12FF80

 

主函b

主函a

 

 

副函*a

副函*b

 

接下來的 “依址取值” 的概念如果沒有的話,請回到 01_初學指標請進 – 指標與位址 看熟。

 

當 Swap_A 執行完,準備要返回 main() 時,由於副函a存的是12FF60位址值,所以每次用 c = *a 等之類的運算,全都是以位址的概念進行 assign,最後發現,*a(就是位址12FF60的值)和*b(就是位址12FF54的值)已對換。記憶體配置圖如下

儲存值

10

5

 

……..

12FF60

12FF54

記憶體位址

12FF54

12FF60

……..

……..

12FF7C

12FF80

 

主函b

主函a

 

 

副函*a

副函*b

 

Swap_A(a,b) 執行完回到 main()後,副函數的指標a和指標b的記憶體位址,一樣又還給了系統

儲存值

10

5

 

……..

……..

……..

記憶體位址

12FF54

12FF60

……..

……..

……..

……..

 

主函b

主函a

 

 

 

 

 

最後完成了主函數變數a和變數b的位址交換。

在這篇結束時,丟出一個問題請各位想想:如果今天在 main 函式裡面有 int *a, *b,那我的副函式該如何寫才能夠使得 main 函數裡 a, b 的內函值完成swap?這是個有趣的問題…

arrow
arrow
    全站熱搜

    Edison 發表在 痞客邦 留言(4) 人氣()