除指向数据的指针外,C 语言还支持函数指针:保存函数入口地址,并通过指针间接调用函数。当需要在运行时选择不同的函数实现(例如不同的比较规则)时,函数指针是常用手段。

为何使用函数指针

直接写函数名调用即可满足多数需求。若调用方(如标准库排序)只提供统一接口,而具体行为由程序员提供,则可将函数地址作为参数传入。典型例子是 qsort 的比较函数。

声明方式

void (*pf)(int);

含义可理解为:pf 是指针,指向“接受一个 int 参数、返回 void”的函数。*pf 两侧的括号不可缺少;若省略,声明将变为返回指针的函数,语义不同。

char *(*pf)(int *);
/* pf 指向的函数:参数为 int *,返回 char * */

赋值与调用

函数名在表达式中可转换为函数指针;也可显式使用 & 取地址:

#include <stdio.h>

void someFunction(int arg) {
    printf("someFunction 被调用,参数是 %d\n", arg);
}

int main(void) {
    void (*pf)(int);
    pf = someFunction;   /* 或 pf = &someFunction; */

    pf(5);
    return 0;
}

示例:qsort 与自定义比较函数

#include <stdio.h>
#include <stdlib.h>

int compare(const void *left, const void *right) {
    return *(int *)right - *(int *)left;   /* 降序 */
}

int main(void) {
    int iarray[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    int n = (int)(sizeof(iarray) / sizeof(iarray[0]));

    qsort(iarray, n, sizeof(int), compare);

    for (int i = 0; i < n; i++) {
        printf("%d ", iarray[i]);
    }
    printf("\n");
    return 0;
}

更换比较函数即可改变排序规则,而无需修改 qsort 的实现。

函数指针数组

可将多个函数指针存入数组,按索引选择调用,常用于菜单、状态机等:

#include <stdio.h>

void f1(int var) { printf("f1,参数 %d\n", var); }
void f2(int var) { printf("f2,参数 %d\n", var); }
void f3(int var) { printf("f3,参数 %d\n", var); }

int main(void) {
    void (*funcs[3])(int) = {f1, f2, f3};

    for (int c = 0; c < 3; c++) {
        funcs[c](c);
    }
    return 0;
}

常见应用场景

  • 标准库回调:排序、查找等接口传入比较或处理函数。
  • 事件驱动或异步逻辑中的回调函数。
  • 命令表、状态机:用函数指针数组映射编号与处理函数。

理解函数指针有助于阅读标准库与第三方 API 中“传入函数地址”的接口;其语法与指针基础密切相关。