main 及多個函式組成。return 表達式; 將值傳回呼叫者。void 表示無返回值。編譯器依據原型進行:
/* 原型 */
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,強制要求原型可見。
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 f(void) { if (error) return; ... }:提前返回合法且常用於錯誤快速退出。return;。return;,集中錯誤處理路徑更清晰。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 保護輸入、結構體封裝多參數」 的工程化規範。