在 C 語言中,函數名本質上就是指向函數程式碼區的指標。掌握函數指標可實現回調、狀態機、策略模式等進階設計模式,是系統級開發的核心技能。
返回類型 (*指標變數名)(參數類型列表);
範例:int (*calculate)(int, int); 宣告一個指向「接受兩 int 回傳 int」函數的指標。
#include <stdio.h>
int add(int n, int m) { return n + m; }
int sub(int n, int m) { return n - m; }
int main() {
int n = 10, m = 5;
int (*calculate)(int, int); // 宣告函數指標
calculate = add; // 指向 add
printf("add: %d\n", calculate(n, m)); // 15
calculate = sub; // 指向 sub
printf("sub: %d\n", calculate(n, m)); // 5
return 0;
}
注意:呼叫時 calculate(n, m) 與 (*calculate)(n, m) 等價,前者為語法糖。函數指標嚴格檢查簽名(回傳型別、參數型別、參數個數)必須完全一致。
將多個同簽名函數放入陣列,配合枚舉索引,實現「資料驅動邏輯」。
#include <stdio.h>
typedef enum { DUMP, SECOND_CHANCE, MARRIAGE } ResponseType;
typedef struct {
const char* name;
ResponseType type;
} Response;
void dump(Response r) { printf("dump %s\n", r.name); }
void second_chance(Response r) { printf("second_chance %s\n", r.name); }
void marriage(Response r) { printf("marriage %s\n", r.name); }
int main() {
Response rs[] = {
{"Mike", DUMP},
{"Luis", SECOND_CHANCE},
{"Matt", SECOND_CHANCE},
{"William", MARRIAGE}
};
void (*replies[])(Response) = { dump, second_chance, marriage };
for (int i = 0; i < 4; ++i) {
replies[rs[i].type](rs[i]); // 根據類型直接調用對應函數
}
return 0;
}
輸出:
dump Mike
second_chance Luis
second_chance Matt
marriage William
| 場景 | 說明 | 關鍵技術 |
|---|---|---|
| 回調函數 | 庫函數接受使用者函數指標,事件發生時調用 | qsort 比較函數、訊號處理 signal() |
| 狀態機 | 每個狀態對應一個處理函數,狀態轉移即修改函數指標 | 函數指標陣列 + 狀態枚舉 |
| 策略模式 | 執行時動態切換演算法(排序、壓縮、加密) | 結構體內嵌函數指標 |
| 動態載入 | dlopen/dlsym 取得函數位址賦給函數指標 | 外掛架構、熱更新 |
int *func() 是「回傳指標的函數」,非函數指標。必須加括號 int (*func)()if (func_ptr)__cdecl, __stdcall 等一致typedef int (*BinaryOp)(int, int); // 定義型別別名
BinaryOp ops[] = { add, sub, mul, div };
int calculate(BinaryOp op, int a, int b) { return op(a, b); }
使用 typedef 大幅提升可讀性,特別是函數指標作為參數或回傳值時。