C 語言的函式呼叫者都是以 Call by Value 的機制將參數值傳遞給函式。 所謂 Call by Value 就是說當函式開始執行的時候, 另外佔用一段屬於它自己的記憶體,並把參數的值從呼叫者那裡抄過來。 因此,在函式中做的任何數值改變,除了明確 return 回去給呼叫者的數值之外, 在函式與其呼叫者之間,即使有同樣名字的變數,它們的存在也是戶不相干的。 以下我們以兩個例子來說明這個機制。 先看一個簡單的例子。
#include <stdio.h> /* 測試 call by value 的變數傳送機制 (test-callvalue.c) */ void test(int); main() { int x=2; printf("x of main() at %u\n", &x); printf("x of main() before = %d\n", x); test(x); printf("x of main() after = %d\n", x); } void test(int x) { printf(" x of test() at %u\n", &x); printf(" x of test() before = %d\n", x); x = x*x; printf(" x of test() after = %d\n", x); }
觀察兩個 x 的地址不同,在 test() 中的計算結果, 只要沒有明確地 return 回來,就不會影響 main() 中的值。x of main() at 4026530500 x of main() before = 2 x of test() at 4026530468 x of test() before = 2 x of test() after = 4 x of main() after = 2
其次,我們詳細地說明第二個例子。 回顧 test-ipow.c, 當呼叫 ipow(2, i) 的時候, 是把 base 的值定義成 2,把 exp 的值定義成 i 的值。 也就是相當於在 ipow() 裡面先執行了
base = 2;這兩個指令。 在 main() 裡面,i 的值並不受 ipow() 的影響。 而當 ipow() 執行結束時, 它把 ans 的值傳回來 main(), 然後就將所有關於 ipow() 的資料從記憶體中清除了。 就好像將 main() 裡面的數值抄到另一張計算紙上, 在那邊作計算,算好了之後,把答案抄回來,然後立刻就扔掉那張計算紙。
exp = i;
說得更技術一點兒。 當一個程式呼叫 ipow(2, i) 的時候, 作業系統在記憶體中保留了某段位址,記錄
base exp i ans這些變數。當 ipow() 執行了 return ans; 之後, 這些位址就全部被清除了。 當下次又呼叫 ipow(-3, i) 的時候, 再另起爐灶,全部重來一遍。 所以,在前面的 main() 裡面, 一共令 ipow() 的四個變數
base exp i ans在記憶體中緣生緣滅 20 個輪迴。
這種將數值 從一個函式複製到另一個函式 去執行的作法, 稱為值呼叫 (call by value)。
C 函式的參數,凡是普通變數,都採用值呼叫。因為 ipow(2, i) 和 ipow(-3, i) 裡面的 i, 只是將它的值複製一份去 ipow() 裡面而已。 這個值在 ipow() 之內不管做了什麼改變,都不關呼叫者 (caller) 的事。 所以在 ipow() 執行結束之後,i 的值不會改變。
說得再詳細一點,在 main() 裡面有一個以 i 為名的變數, 在 ipow() 裡面有一個以 exp 為名的變數。 這兩個變數在記憶體中佔有不同的地址編號。 只有當 ipow() 一開始的時候, 它們的值一樣 (exp 抄了 i 的值過來)。 此後,i 和 exp 是風馬牛不相及的。
基於這個道理,ipow() 可以改寫如下,而不必擔心會影響到 main() 裡面 i 的值。
/* 整數的非負整數次方函式,第二版 */ int ipow(int base, int exp) { int ans=1; for (; 0<exp; --exp) ans *= base; return ans; }
習題
double ipower(int base, int exp)當它遇到 exp 是負整數的時候也會算對 (只要在 double 容許的精度範圍內)。 寫一個 main() 來測試兼示範你的 ipower()。
注意:此處所有文件均為原著,個別的版權宣告日後會一一公布, 整體版面設計亦尚未完成。但仍請勿抄襲文字與圖片,以免觸犯著作權法。
Created: Apr 1, 2000
Last Revised: Feb 25, 2001
© Copyright 2001 Wei-Chang Shann 單維彰