隨著程式規模增長,模組化設計成為必然選擇。C 語言以函數為基本模組單元,通過「自頂向下、逐步求精」將複雜問題分解為獨立功能單元。本文系統講解函數定義、聲明、調用、參數傳遞、遞歸等核心機制,並以「計算某日是當年第幾天」貫穿實例。
// 1. 判斷閏年
int leap(int year) {
return (year%4==0 && year%100!=0) || year%400==0;
}
// 2. 某月天數(調用 leap)
int month_days(int year, int month) {
switch(month) {
case 1: case 3: case 5: case 7: case 8: case 10: case 12: return 31;
case 2: return leap(year) ? 29 : 28;
default: return 30;
}
}
// 3. 累加天數(調用 month_days)
int days(int year, int month, int day) {
int sum = 0;
for (int i = 1; i < month; i++) sum += month_days(year, i);
return sum + day;
}
// 主程式:組裝模組
int main() {
int y, m, d;
scanf("%d-%d-%d", &y, &m, &d);
printf("%d-%d-%d 是 %d 年的第 %d 天\n", y, m, d, y, days(y,m,d));
}
設計精髓:每個函數單一職責,通過參數傳遞與返回值協作,主函數僅負責流程編排。
返回類型 函數名(類型 形參1, 類型 形參2, ...) {
// 函數體
return 表達式; // 無返回值用 void + return;
}
| 分類維度 | 類別 | 說明 |
|---|---|---|
| 定義來源 | 庫函數 | 系統提供,含頭文件直接用 |
| 用戶自定義 | 需聲明/定義後使用 | |
| 返回值 | 有返回值 | 返回具體類型結果 |
| 無返回值 | void,完成特定動作 | |
| 參數 | 無參 | 不傳遞數據 |
| 有參 | 含形參/實參傳遞 |
返回類型 函數名(參數類型1, 參數類型2, ...); // 參數名可省略
| 場景 | 處理方式 |
|---|---|
| 被調用函數在主調用函數後(同文件) | 必須在主調用前聲明 |
| 被調用函數在主調用函數前(同文件) | 可省略聲明(定義即聲明) |
| 被調用函數在其他文件 | 建立頭文件 .h,主調用 #include |
void fun(int num) { num = 20; printf("%d\n", num); } // 輸出 20
int main() { int x = 10; fun(x); printf("%d\n", x); } // 輸出 10
本質:實參值複製給形參,形參在棧幀中獨立存在,函數結束銷毀,不影響實參。
int f(int a, int b, int c) { return a + b * c; }
int x = 3;
int y = f(x, x++, x++); // 參數求值順序由編譯器決定,結果不可移植!
鐵律:實參表達式勿包含副作用(++/--、賦值、函數調用)。
陣列參數退化為指針,形參接收首元素位址,函數內修改元素影響原陣列。
void input(int a[], int n) { for(i=0;i
void even(int x) {
for (int i=2; i<=x/2; i++)
if (prime(i) && prime(x-i))
printf("%d=%d+%d\n", x, i, x-i);
}
int prime(int n) {
for (int i=2; i*i<=n; i++) if (n%i==0) return 0;
return 1;
}
int fact(int n) {
if (n <= 1) return 1; // 遞歸出口(基線條件)
return n * fact(n-1); // 遞歸步驟
}
遞歸三要素:① 明確基線條件 ② 縮小問題規模 ③ 正確組合子問題結果。
函數是 C 語言構建大型程式的基石。掌握單一職責拆分、聲明與定義分離、值傳遞語義、陣列退化規則、遞歸終止條件,即可寫出結構清晰、可複用、易測試的模組化代碼。養成「先寫頭文件聲明,再實現函數體,最後組裝主流程」的開發習慣,是邁向工程師的關鍵一步。