這是一個討論很久的名詞問題。
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?這是個有趣的問題…