函数指针详解
函数指针是 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 常见错误
-
函数签名不匹配
c// 错误:函数指针期望两个参数,但函数只有一个 int (*ptr)(int, int) = single_param_func; // 编译警告/错误 -
未初始化就调用
cint (*ptr)(int, int); ptr(1, 2); // 未定义行为!可能崩溃 -
混淆函数指针和指针函数
c// 错误:这是指针函数声明,不是函数指针 int *func(int a, int b); // 返回 int* 的函数
8.2 注意事项
- 函数指针必须与目标函数签名完全匹配(返回类型 + 参数列表)
- 调用前确保函数指针已正确初始化
- 使用 typedef 提高代码可读性
- 在嵌入式系统中,函数指针会增加少量 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 语言高级开发者的必经之路!