函數是 C 語言模組化程式設計的基石。本文系統整理函數定義、呼叫慣例、參數機制、回傳值、遞迴、作用域與儲存類別,並附上實戰範例與常見誤區。
[回傳型別] 函數名稱 ([參數列表]) {
執行區塊;
return 運算式;
}
int(C99 已移除,建議明確指定)void 而非空括號main 之後需前置宣告| 術語 | 定義 | 特性 |
|---|---|---|
| 實參 | 呼叫時傳入的值/變數/運算式 | 必須具備確定值 |
| 形參 | 函數定義接收用的區域變數 | 僅在函數內部有效,呼叫時配置、返回時釋放 |
值傳遞:形參獲得實參副本,函數內修改不影響外部。
void swap(int a, int b) { int t=a; a=b; b=t; } // 無效
void swap(int *a, int *b) { int t=*a; *a=*b; *b=t; } // 需傳址
return 運算式; 回傳單一值void 函數僅能 return; 提前結束,不可帶運算式遞迴三要素:基礎情況、遞迴步驟、收斂保證。
// 階乘
int fact(int n) {
if (n < 0) return 0;
if (n <= 1) return 1;
return n * fact(n - 1);
}
// 猴子摘桃子(逆向遞迴)
int peach(int day) {
if (day == 10) return 1;
return (peach(day + 1) + 1) * 2;
}
遞迴特性:每層擁有獨立區域變數;程式碼不重複;呼叫前陳述正序執行,呼叫後陳述逆序執行;必須有終止條件否則堆疊溢位。
| 類別 | 關鍵字 | 作用域 | 生命週期 | 連結性 |
|---|---|---|---|---|
| 區域自動 | auto (預設) | 區塊內 | 區塊執行期間 | 無 |
| 區域靜態 | static | 區塊內 | 程式全期 | 無 |
| 全域靜態 | static (檔案層級) | 檔案內 | 程式全期 | 內部 |
| 全域外部 | extern (預設) | 整個專案 | 程式全期 | 外部 |
| 暫存器 | register | 區塊內 | 區塊執行期間 | 無 |
void counter(void) {
static int cnt = 0; // 僅初始化一次,保持值
auto int tmp = 0; // 每次呼叫重新初始化
printf("static=%d, auto=%d\n", ++cnt, ++tmp);
}
int main(void) {
for (int i=0; i<3; i++) counter();
// 輸出: static=1, auto=1 / static=2, auto=1 / static=3, auto=1
}
static 函數:僅限本編譯單元可見,不同檔案可同名extern 函數:預設,可跨檔案連結double fare(double km, int hour) {
const double base = 13.0; // 起步價含 3 km
const double rate = 2.3; // 每公里
const double night_extra = 0.2; // 夜間加成 20%
const double oil = 1.0; // 燃油費
double dist = fmax(km - 3, 0);
double unit = (hour >= 23 || hour < 5) ? rate * 1.2 : rate;
return base + dist * unit + oil;
}
static → ✅ 僅區域變數可用 static-Wmissing-prototypesregister 修飾陣列/結構體 → ✅ 僅限標量區域變數/形參,且編譯器可忽略