函數
-
基本觀念及術語
- 在 C 語言中, 如果函數沒有傳回值, 必須宣告成 void ...(...);
如果不寫, 表示傳回值是整數: int ...(...).
- 如果函數不需要參數, 則應宣告其參數為 void.
void *
表示指到任意型別的指標.
- 函數的 declaration (宣告):
告訴編譯器「有人會提供某某函數給我們用」的這個動作.
至少要有函數的名稱, 往往也包含了傳回值型別及參數的個數型別
- 函數的 signature (簽名?): 包含函數的名稱,
及參數的個數、型別
- 函數的 prototype (原型): 函數的 signature
外加傳回值型別
- definition 定義: 函數真正的內容 (每一步該怎麼做 ...)
- invocation 呼叫
- formal argument/parameter 形式參數: 在副程式的 definition
的參數列當中出現的東西
- actual argument/parameter 實際參數: 在呼叫副程式
(invocation) 的地方出現
-
Call-by-value (以值呼叫)
- 例: 寫一個副程式, 交換兩個 double 變數的內容:
void
swap(double x, double y) { ... }
再從主程式中呼叫
swap(a, b) 為何無法達到交換 a b 的效果? 因為 C 的函數呼叫方式為
call-by-value, 形式參數其實真的是另外一個新的變數,
一個新的盒子, 只不過它的內容拷貝自實際參數而已.
- 如果需要副程式修改傳進去的參數, 必須傳入位址: 以
void
swap(double * x, double * y)
宣告; 以 swap(&a,
&b) 呼叫. 雖然仍舊是 call-by-value, 但這回拷貝的是位址,
所以副程式有辦法透過它修改實際參數.
- 陣列參數: 在參數列中, 陣列完全同於指標,
而且一維陣列的大小可以不必宣告; 多維陣列的第一個 dim 也不必.
... arg[][10] ... 可; ... arg[10][] ... 錯!
-
參數中的 const
- 在變數宣告中, const 表示你對 compiler 的承諾; 在參數宣告中
const 表示副程式對呼叫程式的承諾,
而不是副程式對呼叫程式的要求.
- 例:
int strcmp(char const * p, char const *
q);
與 char * strcpy(char * dst, char const *
src);
- 結論 (配合 call-by-calue): 這就是為什麼參數列上的 const
沒有太大的用處: 好像副程式在對呼叫者說: 我像你借一本書來拷貝,
把原版還給你; 我向你保証不會去塗改我的抄本.
- Q: 若有
char name[20];
則 strcpy(name,
"Sam");
是正確的; 但是 strcpy("Sam", name);
是錯的, 錯在前面還是後面?
- Q: 既然把程式中 (包含 include 檔) 所有的 const 完全拿掉,
對程式的執行效果完全沒有影響, 為何自找麻煩?
- 結論: 副程式的參數列中, 把指標宣告成常數沒有太大的意義;
通常都是把指標指到的東西宣告成常數.
- Recursion (遞迴) 及 activation
record