函數指針指向可執行代碼入口地址,本質是代碼區指針。聲明語法:
// 函數原型
int max(int a, int b);
// 函數指針變數聲明 (讀法:p 是指針,指向參數為兩 int、返回 int 的函數)
int (*p)(int, int);
// 賦值 (函數名隱式轉換為地址,& 可省略)
p = max;
p = &max;
// 調用 (三種等價寫法)
int r1 = max(3, 5);
int r2 = p(3, 5);
int r3 = (*p)(3, 5);
場景:鏈表查找,比較邏輯由調用者決定 (整數、字串、結構體...)
// 通用查找:節點、目標值、比較函數指針
typedef struct Node { void *data; struct Node *next; } Node;
Node* list_find(Node *head, void *target, int (*cmp)(void*, void*)) {
for (Node *cur = head; cur; cur = cur->next)
if (cmp(cur->data, target) == 0)
return cur;
return NULL;
}
// 整數比較
int cmp_int(void *a, void *b) { return *(int*)a - *(int*)b; }
// 字串比較
int cmp_str(void *a, void *b) { return strcmp((char*)a, (char*)b); }
// 使用
int key = 42;
Node *found = list_find(head, &key, cmp_int);
char *name = "Alice";
found = list_find(head, name, cmp_str);
場景:字元運算符分發、狀態機、命令解析
// 運算函數
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int mul(int a, int b) { return a * b; }
int div(int a, int b) { return b ? a / b : 0; }
// 跳轉表:索引 = 運算符字元 - '+'
int (*ops[4])(int, int) = {add, sub, mul, div}; // + - * /
int calculate(int a, char op, int b) {
int idx = op - '+';
if (idx >= 0 && idx < 4)
return ops[idx](a, b);
return 0; // 無效運算符
}
優勢:O(1) 分發、易擴展 (新增運算符只加數組元素)、代碼緊湊、利於編譯器優化 (間接跳轉)。
typedef struct {
int x, y;
void (*draw)(struct Shape*);
double (*area)(struct Shape*);
} Shape;
void draw_rect(Shape *s) { ... }
double area_rect(Shape *s) { ... }
Shape rect = {10, 20, draw_rect, area_rect};
rect.draw(&rect); // 多態調用
int cmp_int(const void *a, const void *b) {
return *(const int*)a - *(const int*)b;
}
int arr[] = {5, 2, 8, 1, 9};
qsort(arr, 5, sizeof(int), cmp_int); // 排序
int key = 8;
int *found = bsearch(&key, arr, 5, sizeof(int), cmp_int); // 二分查找
// 無 typedef
int (*(*fp[10])(int, char*))(double);
// 有 typedef
typedef int (*FuncPtr)(double); // 返回 int,參數 double
typedef FuncPtr (*Factory)(int, char*); // 返回 FuncPtr,參數 int, char*
Factory fp[10]; // 清晰:10 個工廠函數指針
int (*arr[3])(int); // 3 個函數指針的數組
int (*(*parr)[3])(int); // 指向「3 個函數指針數組」的指針
void* 可作為通用參數/返回類型,但需調用端強轉 (類型安全由程序員保證)
typedef enum {IDLE, RUN, PAUSE, STOP} State;
typedef enum {EV_START, EV_PAUSE, EV_RESUME, EV_STOP} Event;
typedef State (*Handler)(State, Event);
State handle_idle(State s, Event e) { return e==EV_START ? RUN : IDLE; }
State handle_run(State s, Event e) {
if(e==EV_PAUSE) return PAUSE;
if(e==EV_STOP) return STOP;
return RUN;
}
// ...
Handler table[4][4] = {
[IDLE] = {handle_idle, handle_idle, handle_idle, handle_idle},
[RUN] = {handle_run, handle_run, handle_run, handle_run},
// ...
};
State current = IDLE;
Event evt = EV_START;
current = table[current][evt](current, evt); // 表驅動狀態轉移
函數指針是 C 語言實現多態、回調、泛型、動態分發的核心機制。掌握:
typedef 分層簡化複雜類型qsort, bsearch, atexit, signal) 均依賴函數指針善用函數指針,能寫出可擴展、可測試、可復用的 C 代碼架構。