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

C 語言函數指針完全指南:聲明、調用、回調、跳轉表與泛型演算法

     編輯:關於C語言

函數指針基礎

函數指針指向可執行代碼入口地址,本質是代碼區指針。聲明語法:


// 函數原型
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);

核心應用場景

1. 回調函數:泛型演算法與特定邏輯分離

場景:鏈表查找,比較邏輯由調用者決定 (整數、字串、結構體...)


// 通用查找:節點、目標值、比較函數指針
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);

2. 跳轉表:替代冗長 switch-case

場景:字元運算符分發、狀態機、命令解析


// 運算函數
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) 分發、易擴展 (新增運算符只加數組元素)、代碼緊湊、利於編譯器優化 (間接跳轉)。

3. 函數指針作為結構體成員:面向對象雛形


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); // 多態調用

4. 標準庫 qsort/bsearch 回調


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 簡化複雜聲明


// 無 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* 可作為通用參數/返回類型,但需調用端強轉 (類型安全由程序員保證)
  • 調用約定必須一致 (cdecl/stdcall/fastcall...)

實戰模式:狀態機表驅動


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 語言實現多態、回調、泛型、動態分發的核心機制。掌握:

  1. 聲明語法讀法 (右左法則)
  2. typedef 分層簡化複雜類型
  3. 回調模式:演算法框架與業務邏輯解耦
  4. 跳轉表:O(1) 分發替代 switch
  5. 標準庫算法 (qsort, bsearch, atexit, signal) 均依賴函數指針

善用函數指針,能寫出可擴展、可測試、可復用的 C 代碼架構。

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