函數


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