C语言 函数指针

函数指针详解

函数指针是 C 语言中一种特殊的指针类型,它指向函数的入口地址 ,通过它可以间接调用函数。函数指针是实现回调函数、状态机、插件架构等高级编程模式的核心机制。


一、基本概念

1.1 什么是函数指针?

  • 函数在内存中也有固定的存储地址(即函数的入口地址)
  • 函数指针就是存储这个地址的"容器"
  • 通过函数指针可以间接调用函数 ,甚至动态切换调用的函数

1.2 函数指针 vs 指针函数

类型 含义 声明示例
函数指针 指向函数的指针 int (*func_ptr)(int, int);
指针函数 返回指针的函数 int* func(int a, int b);

💡 记忆技巧:"函数指针" = 指针,"指针函数" = 函数


二、函数指针的声明与初始化

2.1 声明语法

c 复制代码
返回类型 (*指针名)(参数列表);

2.2 示例

c 复制代码
// 声明一个函数指针,指向返回 int、接受两个 int 参数的函数
int (*add_ptr)(int, int);

// 定义实际函数
int add(int a, int b) {
    return a + b;
}

// 初始化函数指针
add_ptr = add;        // 方式1:直接赋值函数名
add_ptr = &add;       // 方式2:取函数地址(& 可省略)

2.3 使用 typedef 简化声明

c 复制代码
// 为函数指针类型创建别名
typedef int (*Operation)(int, int);

Operation add_ptr = add;
Operation sub_ptr = subtract;

三、通过函数指针调用函数

3.1 两种调用方式

c 复制代码
// 方式1:显式解引用
result = (*add_ptr)(3, 5);

// 方式2:直接调用(推荐,更简洁)
result = add_ptr(3, 5);

3.2 完整示例

c 复制代码
#include <stdio.h>

int add(int a, int b) { return a + b; }
int multiply(int a, int b) { return a * b; }

int main() {
    int (*func_ptr)(int, int);
    
    func_ptr = add;
    printf("Add: %d\n", func_ptr(3, 5)); // 输出: 8
    
    func_ptr = multiply;
    printf("Multiply: %d\n", func_ptr(3, 5)); // 输出: 15
    
    return 0;
}

四、函数指针作为函数参数(回调函数)

4.1 基本用法

c 复制代码
// 接受函数指针作为参数的函数
void execute_operation(int a, int b, int (*operation)(int, int)) {
    int result = operation(a, b);
    printf("Result: %d\n", result);
}

// 调用
execute_operation(10, 5, add);        // Result: 15
execute_operation(10, 5, multiply);   // Result: 50

4.2 经典应用:qsort 排序

c 复制代码
#include <stdio.h>
#include <stdlib.h>

// 比较函数
int compare_ints(const void *a, const void *b) {
    return (*(int*)a - *(int*)b);
}

int main() {
    int arr[] = {5, 2, 8, 1, 9};
    int n = sizeof(arr) / sizeof(arr[0]);
    
    // qsort 使用函数指针进行通用排序
    qsort(arr, n, sizeof(int), compare_ints);
    
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]); // 输出: 1 2 5 8 9
    }
    return 0;
}

五、函数指针数组

5.1 声明与初始化

c 复制代码
// 函数指针数组:管理多个相同签名的函数
int (*operations[2])(int, int) = {add, multiply};

// 使用 typedef 更清晰
typedef int (*Op)(int, int);
Op operations[] = {add, multiply, subtract, divide};

5.2 实际应用:简易计算器

c 复制代码
#include <stdio.h>

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 != 0 ? a / b : 0; }

int main() {
    typedef int (*Calculator)(int, int);
    Calculator ops[] = {add, sub, mul, div};
    char symbols[] = {'+', '-', '*', '/'};
    
    int choice, a = 10, b = 5;
    printf("选择操作 (0:+, 1:-, 2:*, 3:/): ");
    scanf("%d", &choice);
    
    if (choice >= 0 && choice < 4) {
        int result = ops[choice](a, b);
        printf("%d %c %d = %d\n", a, symbols[choice], b, result);
    }
    return 0;
}

六、高级用法

6.1 指向函数指针的指针

c 复制代码
int (**ptr_to_func_ptr)(int, int) = &add_ptr;
int result = (*ptr_to_func_ptr)(3, 5); // 等价于 add_ptr(3, 5)

6.2 函数指针作为返回值

c 复制代码
// 返回函数指针的函数
int (*get_operation(char op))(int, int) {
    switch(op) {
        case '+': return add;
        case '-': return sub;
        case '*': return mul;
        default: return NULL;
    }
}

// 使用
int (*func)(int, int) = get_operation('+');
int result = func(3, 5);

使用 typedef 让返回值更清晰:

c 复制代码
typedef int (*Operation)(int, int);

Operation get_operation(char op) {
    // ... same as above
}

七、实际应用场景

7.1 事件处理系统

c 复制代码
// 事件处理器映射表
void on_click() { printf("Button clicked!\n"); }
void on_hover() { printf("Mouse hovered!\n"); }

typedef void (*EventHandler)();
EventHandler event_handlers[] = {on_click, on_hover};

// 事件分发
void dispatch_event(int event_type) {
    if (event_type >= 0 && event_type < 2) {
        event_handlers[event_type]();
    }
}

7.2 状态机实现

c 复制代码
// 状态函数
void state_idle();
void state_running();
void state_error();

typedef void (*StateFunc)();
StateFunc current_state = state_idle;

void state_idle() {
    printf("Idle state\n");
    // 某条件满足时切换状态
    current_state = state_running;
}

void state_running() {
    printf("Running state\n");
    // 执行状态逻辑
}

// 主循环
while (1) {
    current_state(); // 动态调用当前状态函数
    delay(1000);
}

7.3 插件架构

c 复制代码
// 插件接口
typedef struct {
    char* name;
    void (*init)();
    void (*execute)();
    void (*cleanup)();
} Plugin;

// 插件实现
void plugin_init() { /* 初始化代码 */ }
void plugin_execute() { /* 执行代码 */ }
void plugin_cleanup() { /* 清理代码 */ }

Plugin my_plugin = {
    "MyPlugin",
    plugin_init,
    plugin_execute,
    plugin_cleanup
};

八、常见错误与注意事项

8.1 常见错误

  1. 函数签名不匹配

    c 复制代码
    // 错误:函数指针期望两个参数,但函数只有一个
    int (*ptr)(int, int) = single_param_func; // 编译警告/错误
  2. 未初始化就调用

    c 复制代码
    int (*ptr)(int, int);
    ptr(1, 2); // 未定义行为!可能崩溃
  3. 混淆函数指针和指针函数

    c 复制代码
    // 错误:这是指针函数声明,不是函数指针
    int *func(int a, int b); // 返回 int* 的函数

8.2 注意事项

  1. 函数指针必须与目标函数签名完全匹配(返回类型 + 参数列表)
  2. 调用前确保函数指针已正确初始化
  3. 使用 typedef 提高代码可读性
  4. 在嵌入式系统中,函数指针会增加少量 RAM 使用

九、综合应用示例:通用排序框架

c 复制代码
#include <stdio.h>
#include <string.h>

// 比较函数类型
typedef int (*CompareFunc)(const void*, const void*);

// 通用冒泡排序
void bubble_sort(void* arr, int count, int size, CompareFunc compare) {
    char* base = (char*)arr;
    char temp[100]; // 足够大的临时缓冲区
    
    for (int i = 0; i < count - 1; i++) {
        for (int j = 0; j < count - 1 - i; j++) {
            if (compare(base + j * size, base + (j + 1) * size) > 0) {
                // 交换元素
                memcpy(temp, base + j * size, size);
                memcpy(base + j * size, base + (j + 1) * size, size);
                memcpy(base + (j + 1) * size, temp, size);
            }
        }
    }
}

// 具体比较函数
int compare_ints(const void* a, const void* b) {
    return (*(int*)a - *(int*)b);
}

int compare_strings(const void* a, const void* b) {
    return strcmp(*(char**)a, *(char**)b);
}

int main() {
    // 整数排序
    int nums[] = {5, 2, 8, 1, 9};
    bubble_sort(nums, 5, sizeof(int), compare_ints);
    
    // 字符串排序
    char* strings[] = {"banana", "apple", "cherry"};
    bubble_sort(strings, 3, sizeof(char*), compare_strings);
    
    return 0;
}

总结

函数指针是 C 语言的强大特性,它提供了:

  • 运行时动态调用函数的能力
  • 解耦代码,提高模块化程度
  • 实现回调机制事件驱动编程
  • 构建通用算法(如排序、搜索)
  • 实现状态机插件系统

掌握函数指针是成为 C 语言高级开发者的必经之路!

相关推荐
王老师青少年编程2 小时前
csp信奥赛C++高频考点专项训练之贪心算法 --【排序贪心】:纪念品分组
c++·算法·贪心·csp·信奥赛·排序贪心·纪念品分组
贾斯汀玛尔斯2 小时前
每天学一个算法--贪心算法(Greedy Algorithm)
算法·贪心算法
前端摸鱼匠2 小时前
【AI大模型春招面试题24】什么是“注意力分数”?如何计算?其大小反映了什么?
人工智能·算法·ai·面试·大模型·求职招聘
MicroTech20252 小时前
融合残差结构的量子电路算法:MLGO微算法科技拓展量子机器学习频谱边界
科技·算法·机器学习
H_BB2 小时前
动态规划详解
c++·算法·动态规划
算法鑫探2 小时前
贪心算法(C 语言实现)及经典应用
c语言·数据结构·算法·贪心算法
始三角龙2 小时前
LeetCode hoot 100 -- 和为K的子数组
算法·leetcode·职场和发展
ccice012 小时前
python爬虫——爬取全年天气数据并做可视化分析
开发语言·爬虫·python
_深海凉_2 小时前
LeetCode热题100-最长递增子序列
算法·leetcode·职场和发展