函式是 C 語言模組化的基本單元。本文深入剖析 return 回傳值機制、傳統 vs 現代函式宣告風格、陣列作為參數的退化規則、遞迴函式設計模式,並提供標準庫級錯誤處理範例。
return 語句語義return 表達式; // 計算表達式值,複製至呼叫端暫存器/棧框
return (表達式); // 等價,括號可加可不加
return; // 僅用於 void 函式,直接返回控制權
return(控制流離開函式)。double→int 截斷)。void 函式不可用於運算式中(x = f(); 編譯錯誤)。// 錯誤:定義 double 卻 return int
double bad() { return 3; } // 隱含轉 3.0,但誤導維護者
// 正確:明確回傳型別
double good() { return 3.0; }
| 風格 | 語法 | 參數檢查 | 適用場景 |
|---|---|---|---|
| 傳統 (K&R) | int max(); | 無(呼叫端隨意傳參) | 舊碼維護 |
| 現代 (ANSI) | int max(int a, int b); | 完整型別/個數檢查 | 所有新專案 |
| 現代簡化 | int max(int, int); | 型別檢查,參數名可省略 | 標頭檔常用 |
強制要求:C99 起禁止隱含函式宣告(呼叫前必須可見宣告或定義)。
int/char 且未出現參數型別轉換需求(舊式隱含 int 規則,現代不建議依賴)。#include <header.h> 已含宣告。| 模式 | 語法 | 實際傳遞 | 函式內可修改原陣列? |
|---|---|---|---|
| 單一元素 | f(arr[i]) | 值傳遞 int | 否 |
| 整個陣列 | f(arr) | 指標 int*(首元素位址) | 是 |
void f1(int arr[]); // 建議:語意清楚
void f2(int arr[10]); // 長度被忽視,僅文件用
void f3(int *arr); // 本質:指標
函式無法得知陣列長度,必須額外傳遞 size_t n。
void print_nonneg(int val) {
printf("%d ", val > 0 ? val : 0);
}
int main() {
int a[5];
for (int i=0; i<5; ++i) scanf("%d", &a[i]);
for (int i=0; i<5; ++i) print_nonneg(a[i]); // 元素傳值
}
void print_mat(int mat[][4], int rows) { // 或 int (*mat)[4]
for (int i=0; i
long long fact(int n) {
if (n <= 1) return 1; // 基底
return n * fact(n - 1); // 遞迴步驟 + 縮減
}
// 非尾端:乘法在遞迴返回後
long long fact(int n) { return n<=1?1:n*fact(n-1); }
// 尾端:累積器帶入參數
long long fact_tail(int n, long long acc) {
if (n <= 1) return acc;
return fact_tail(n-1, n*acc); // 最後動作是呼叫自身
}
// GCC -O2 可優化為迴圈,避免棧溢位
stdarg.h)
#include
double average(int count, ...) {
va_list ap;
va_start(ap, count);
double sum = 0;
for (int i=0; i
int cmp_int(const void *a, const void *b) {
return *(int*)a - *(int*)b;
}
qsort(arr, n, sizeof(int), cmp_int); // 標準庫回調
size_t len。const 修飾唯讀指標參數(void f(const int *p))。errno 統一專案規範。typedef 簡化(typedef int (*CmpFn)(const void*,const void*);)。函式設計遵循「單一職責、介面最小化、錯誤可檢測」,是構建可維護 C 專案的基石。