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

C 語言函數指針完全指南:聲明、陣列、回調、狀態機應用

     編輯:關於C語言

函數指針聲明語法


// 1. 基本聲明:返回 int,接受兩個 int 參數的函數指針
int (*pfun)(int, int);       // 推薦:參數名可省略
int (*pfun)(int x, int y);   // 含參數名 (僅作文檔)

// 2. 使用 typedef 簡化 (強烈推薦)
typedef int (*BinaryOp)(int, int); // 定義類型別名 BinaryOp
BinaryOp pf;                       // 變數聲明清晰易讀

口訣:從變數名 `pfun` 向外讀:`*` → 指針 → `()` → 函數 → 參數列表 → 返回類型。

基礎範例:動態綁定運算


#include 

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 main() {
    // 1. 單指針變數賦值
    int (*pf)(int, int) = add;
    printf("9 + 3 = %d\n", pf(9, 3)); // 12

    pf = sub; printf("9 - 3 = %d\n", pf(9, 3)); // 6
    pf = mul; printf("9 * 3 = %d\n", pf(9, 3)); // 27
    pf = div; printf("9 / 3 = %d\n", pf(9, 3)); // 3

    // 2. 函數指針陣列:跳躍表 / 命令分發
    int (*ops[4])(int, int) = {add, sub, mul, div};
    char *names[] = {"加", "減", "乘", "除"};
    for (int i = 0; i < 4; i++)
        printf("%s: %d\n", names[i], ops[i](9, 3));

    return 0;
}

進階應用 1:回調函數

將函數指針作參數傳遞,實現「控制反轉」。


// 通用數學運算執行器
int execute_op(int (*op)(int, int), int x, int y) {
    return op(x, y); // 回調
}

// 排序比較函數 (qsort 模式)
int cmp_int_asc(const void *a, const void *b) {
    return (*(int*)a - *(int*)b);
}
int cmp_int_desc(const void *a, const void *b) {
    return (*(int*)b - *(int*)a);
}

void sort_demo(int *arr, int n, int (*cmp)(const void*, const void*)) {
    qsort(arr, n, sizeof(int), cmp); // 標準庫回調
}

進階應用 2:狀態機

每個狀態對應一個處理函數,指針指向當前狀態處理器。


typedef enum { STATE_IDLE, STATE_RUN, STATE_STOP } State;
typedef void (*StateHandler)(void);

void idle_handler()  { puts("IDLE: Waiting..."); }
void run_handler()   { puts("RUN:  Processing..."); }
void stop_handler()  { puts("STOP: Halted."); }

StateHandler handlers[] = {idle_handler, run_handler, stop_handler};
State current = STATE_IDLE;

void transition(State next) {
    current = next;
    handlers[current](); // 直接調用對應處理器
}

進階應用 3:C 模擬物件導向 (多態)


typedef struct {
    int (*draw)(void *self);
    int (*area)(void *self);
    // 數據成員...
} ShapeVTable;

typedef struct { ShapeVTable *vptr; int x, y; } Shape;
typedef struct { Shape base; int r; } Circle;
typedef struct { Shape base; int w, h; } Rect;

// 虛函數表實例
ShapeVTable circle_vtbl = {circle_draw, circle_area};
ShapeVTable rect_vtbl   = {rect_draw,   rect_area};

void circle_init(Circle *c, int x, int y, int r) {
    c->base.vptr = &circle_vtbl; c->base.x=x; c->base.y=y; c->r=r;
}
// 調用: shape->vptr->draw(shape); // 動態分發

常見陷阱與最佳實踐

  1. 聲明與定義分離:頭檔僅聲明 `typedef` 與函數原型;實現檔定義函數體。
  2. NULL 檢查:調用前 `if (pf) pf(args);` 防空指針崩潰。
  3. 調用約定一致:嵌入式/Windows API 涉及 `__stdcall`, `__cdecl`, `__fastcall`,指針類型必須匹配(如 `int (__stdcall *pf)(int)`)。
  4. 避免過度嵌套:`void (*(*fp[10])(int))(double)` 這類聲明極難維護,拆解為多層 `typedef`。
  5. 兼容性:C++ 中函數指針可隱式轉換為 `std::function` / lambda (無捕獲)。

總結

函數指針是 C 語言實現**動態行為**、**模組解耦**、**泛型演算法**的核心機制。掌握 `typedef` 簡化聲明、陣列構建跳躍表、參數傳遞實現回調,是進階 C 程式設計師的必備技能。

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