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

C語言函式入門完全指南:原型、參數傳遞、返回值、內部函式與陣列參數深度解析

     編輯:關於C語言

函式基礎概念

  • 函式:完成特定任務的獨立程式碼單元,C 程式由 main 及多個函式組成。
  • 函式原型:宣告函式名、返回型別、參數型別清單。置於檔案開頭或頭文件,供編譯器檢查呼叫正確性。
  • 返回值:return 表達式; 將值傳回呼叫者。void 表示無返回值。

為何需要函式原型?

編譯器依據原型進行:

  1. 參數個數檢查
  2. 參數型別檢查(隱式轉換警告)
  3. 返回型別檢查
/* 原型 */
int some_func(int, char *, long);

/* 錯誤呼叫示範 */
x = some_func(1);                    // 參數太少
x = some_func("hello", 1, "dude");   // 型別錯誤
x = some_func(1, str, 2879, "T");    // 參數太多
long *p = some_func(1, str, 2879);   // 返回型別不符

現代編譯器(GCC/Clang/MSVC)預設開啟 -Wmissing-prototypes,強制要求原型可見。

函式參數數量建議

  • 無硬性限制,但 超過 4 個參數即為代碼異味。
  • 參數過多 → 呼叫開銷大、可讀性差、易誤序。
  • 解決方案:封裝為結構體。
typedef struct {
    int orientation;
    char rpt_name[25];
    char rpt_path[40];
    int destination;
    char output_file[25];
    int starting_page;
    char ending_page;
    char db_name[25];
    char db_path[40];
    int draft_quality;
} RPT_PARMS;

int print_report(const RPT_PARMS *p);  // 單一指標參數

缺點:編譯器無法檢查結構體成員是否完整初始化,需靜態分析或運行期斷言補足。

內部函式

static int open_customer_indexes(void);  // 僅本檔可見
int open_customer_table(void) {          // 外部可見
    ...
    ret = open_customer_indexes();
    ...
}
  • static 限制連結可見性,避免跨檔案同名衝突。
  • 良好習慣:預設所有非介面函式加 static,僅在頭文件宣告公開 API。

void 函式與 return 語句

  • void f(void) { if (error) return; ... }:提前返回合法且常用於錯誤快速退出。
  • 正常流程自然落到函式尾部無需 return;。
  • 避免在多處散落 return;,集中錯誤處理路徑更清晰。

陣列參數傳遞:值傳遞 vs 位址傳遞

值傳遞(實為指標傳遞,但語意為複製)

void byval_func(int arr[]);  // 相當於 int *arr
void byval_func(int *arr);   // 等價寫法

void byval_func(int arr[]) {
    arr[0] = 99;  // 修改原陣列內容!並非複製整個陣列
}

關鍵澄清:C 語言無陣列值傳遞。int arr[] 參數調整為 int *arr,傳遞的是首元素位址。函式內修改 arr[i] 直接影響原陣列。若需真正複製,須手動 memcpy 到區域陣列。

位址傳遞(指標)+ const 保護

void const_func(const int *arr) {  // 承諾不修改
    // arr[0] = 99;  // 編譯錯誤
    printf("%d", arr[0]);
}
  • const int *:指向常數的指標,資料唯讀。
  • int *const:常數指標,指標本身不可改指向。
  • 陣列參數建議預設加 const,除非確需修改。

多維陣列參數

void process_2d(int arr[][COLS], int rows);  // 必須指定除第一維外所有維度
void process_2d(int (*arr)[COLS], int rows); // 等價指標寫法

呼叫時傳遞 arr(退化為指向第一行的指標)。

進階主題:可變參數、函式指標、回呼

可變參數 <stdarg.h>

#include <stdarg.h>
void log_msg(const char *fmt, ...) {
    va_list ap;
    va_start(ap, fmt);
    vprintf(fmt, ap);
    va_end(ap);
}

函式指標型別別名

typedef int (*cmp_func_t)(const void *, const void *);
void my_qsort(void *base, size_t n, size_t sz, cmp_func_t cmp);

回呼模式

void on_data_ready(void (*callback)(int data), int data) {
    callback(data);
}
void my_handler(int d) { printf("got %d\n", d); }
on_data_ready(my_handler, 42);

常見錯誤與最佳實踐清單

錯誤後果正確做法
函式定義前未聲明原型隱式 int 返回,參數檢查失效頭文件統一聲明,.c 開頭包含自身頭文件
陣列參數寫成 int arr[10] 以為大小固定退化為指標,大小資訊丟失寫 int arr[] 或 int *arr,另傳長度參數
忘記 const 導致誤改只讀資料難以除錯的資料損壞參數預設 const,需改才移除
遞迴無基礎案例堆疊溢位明確終止條件,必要時改迭代
函式指標轉型不匹配UB,崩潰嚴格遵循型別,使用 typedef 統一

總結

函式是 C 語言模組化的基石。掌握 原型聲明、參數傳遞語意、const 正確性、內部連結、陣列退化規則,能寫出介面清晰、編譯器可檢查、易於測試與維護的程式碼。建議新專案採用 「頭文件只宣告、.c 實作、static 隱藏內部、const 保護輸入、結構體封裝多參數」 的工程化規範。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved