函數指標陣列 (Array of Function Pointers) 讓我們能以索引或鍵值快速查找並呼叫對應函數,是實現命令模式、狀態機、事件分發表、插件系統、系統呼叫表 的基礎結構。本文詳解 C 語言中定義、初始化、呼叫慣例、型別安全與實務應用模式。
// 1. 定義函數指標型別 (提升可讀性)
typedef int (*MathOp)(int a, int b);
// 2. 宣告陣列
MathOp operations[4];
// 3. 目標函數 (簽名必須完全一致)
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; }
// 4. 初始化 (靜態/動態皆可)
MathOp ops[] = { add, sub, mul, div }; // 靜態初始化
// 或
operations[0] = add;
operations[1] = sub;
// ...
// 5. 呼叫
int result = ops[2](10, 5); // mul(10,5) = 50
#include
#include
typedef int (*CalcFunc)(int, int);
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; }
// 指令對應表
typedef struct { char symbol; CalcFunc func; } Command;
Command cmdTable[] = {
{'+', add}, {'-', sub}, {'*', mul}, {'/', div}
};
int main() {
char op; int x, y;
printf("輸入 運算子 數值1 數值2 (如 + 3 5): ");
if (scanf(" %c %d %d", &op, &x, &y) != 3) return 1;
for (size_t i = 0; i < sizeof(cmdTable)/sizeof(cmdTable[0]); i++) {
if (cmdTable[i].symbol == op) {
int result = cmdTable[i].func(x, y);
printf("結果: %d\n", result);
return 0;
}
}
printf("不支援的運算子: %c\n", op);
return 1;
}
typedef enum { IDLE, RUN, PAUSE, ERROR } State;
typedef void (*StateHandler)(void);
void handleIdle() { printf("Idle\n"); }
void handleRun() { printf("Running\n"); }
void handlePause() { printf("Paused\n"); }
void handleError() { printf("Error\n"); }
StateHandler handlers[] = {
[IDLE] = handleIdle,
[RUN] = handleRun,
[PAUSE] = handlePause,
[ERROR] = handleError
};
void dispatch(State s) {
if (s >= 0 && s < sizeof(handlers)/sizeof(handlers[0]) && handlers[s])
handlers[s]();
}
若函數簽名不一致,需定義統一介面 (如 void* ctx) 並在內部轉型:
typedef void (*PluginEntry)(void* context);
void pluginA(void* ctx) { int* p = (int*)ctx; printf("A: %d\n", *p); }
void pluginB(void* ctx) { float* f = (float*)ctx; printf("B: %.2f\n", *f); }
PluginEntry plugins[] = { pluginA, pluginB };
#define MAX_PLUGINS 32
static PluginEntry pluginTable[MAX_PLUGINS];
static int pluginCount = 0;
int RegisterPlugin(PluginEntry entry) {
if (pluginCount >= MAX_PLUGINS) return -1;
pluginTable[pluginCount++] = entry;
return pluginCount - 1; // 回傳 ID
}
void ExecuteAll(void* ctx) {
for (int i = 0; i < pluginCount; i++)
pluginTable[i](ctx);
}
| 議題 | 說明 |
|---|---|
| 簽名完全一致 | 回傳型別、參數型別、參數順序、呼叫慣例 (__cdecl/__stdcall) 必須相同,否則未定義行為 |
| NULL 檢查 | 呼叫前務必檢查指標非 NULL |
| 陣列大小 | 靜態陣列用 sizeof(arr)/sizeof(arr[0]);動態陣列需另存長度 |
| const 正確性 | 若函數不修改狀態,指標型別加 const:typedef int (*Func)(const int) |
| C++ 成員函數 | 非靜態成員函數需物件實例,型別為 Ret (Class::*)(Args...),不可直接存入普通函數指標陣列,需用 std::function、std::bind 或 Lambda 捕獲 this |
函數指標陣列是 C 語言實現多態與動態分發的最輕量機制,掌握其定義、初始化、安全呼叫與擴充模式,能讓系統架構更靈活、擴充性更強。