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

C 語言函數指標陣列實作指南:定義、初始化與應用場景

     編輯:關於C語言

函數指標陣列:建立動態調度表、狀態機與命令表的核心技術

函數指標陣列 (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;
}

進階模式

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]();
}

2. 可變參數/不同簽名的統一封裝

若函數簽名不一致,需定義統一介面 (如 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 };

3. 動態註冊 (插件系統)


#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

應用場景總覽

  • 指令解析器 (Shell、AT 指令、協議解碼)
  • 狀態機 (通訊協議、遊戲 AI、工作流引擎)
  • 中斷向量表 / 系統呼叫表 (OS 核心)
  • 事件回呼註冊表 (GUI 框架、嵌入式驅動)
  • 插件/模組動態載入與執行
  • 查表法優化 (避免大量 if-else/switch 分支預測失敗)

函數指標陣列是 C 語言實現多態與動態分發的最輕量機制,掌握其定義、初始化、安全呼叫與擴充模式,能讓系統架構更靈活、擴充性更強。

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