首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> C 語言入門

C 語言函數深度解析:從參數傳遞、遞迴到儲存類別完整指南

     編輯:C 語言入門

函數是 C 語言模組化程式設計的基石。本文系統整理函數定義、呼叫慣例、參數機制、回傳值、遞迴、作用域與儲存類別,並附上實戰範例與常見誤區。

函數定義與宣告

[回傳型別] 函數名稱 ([參數列表]) {
    執行區塊;
    return 運算式;
}
  • 回傳型別省略預設 int(C99 已移除,建議明確指定)
  • 無參數寫 void 而非空括號
  • 定義在 main 之後需前置宣告

參數傳遞:呼叫端 vs 定義端

術語定義特性
實參呼叫時傳入的值/變數/運算式必須具備確定值
形參函數定義接收用的區域變數僅在函數內部有效,呼叫時配置、返回時釋放

值傳遞:形參獲得實參副本,函數內修改不影響外部。

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;
}

常見錯誤與最佳實務

  1. ❌ 形參宣告 static → ✅ 僅區域變數可用 static
  2. ❌ 忽略函數原型宣告 → ✅ 標頭檔集中宣告,開啟 -Wmissing-prototypes
  3. ❌ 遞迴無終止條件 → ✅ 先寫基礎情況,再寫遞迴步驟
  4. ❌ 濫用全域變數 → ✅ 傾向參數傳遞與回傳值,降低耦合
  5. ❌ register 修飾陣列/結構體 → ✅ 僅限標量區域變數/形參,且編譯器可忽略
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved