在C语言中,"指针函数"和"函数指针"是容易混淆但完全不同的概念。以下是详细的技术解析:
一、指针函数(返回指针的函数)
定义:返回指针类型的函数
声明格式:返回值类型* 函数名(参数列表)
作用:用于返回内存地址(指针),常用于动态内存分配和数据结构操作
// 返回整型指针的函数
int* create_int_array(int size) {
int *arr = (int*)malloc(size * sizeof(int));
return arr; // 返回动态分配的数组首地址
}
// 返回字符串指针的函数
char* get_greeting() {
return "Hello, World!"; // 返回字符串常量地址
}
典型应用场景:
- 工厂模式创建对象
- 内存分配函数(如malloc)
- 链表/树节点创建函数
注意事项:
// 错误示例:返回局部变量地址
int* dangerous_func() {
int local = 100;
return &local; // 局部变量在函数结束后被销毁,返回的指针失效
}
二、函数指针(指向函数的指针)
定义:指向函数入口地址的指针变量
声明格式:返回值类型 (*指针名)(参数列表)
作用:实现回调机制、函数动态调用、策略模式等高级功能
// 声明函数指针类型
typedef int (*MathFunc)(int, int);
// 函数指针的使用示例
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int main() {
MathFunc operation = add;
printf("3+5=%d\n", operation(3,5)); // 输出8
operation = sub;
printf("8-3=%d\n", operation(8,3)); // 输出5
return 0;
}
典型应用场景:
- 事件处理回调(如GUI编程)
- 函数表驱动开发(如状态机)
- 动态库函数调用(dlopen/dlsym)
- 排序算法中的比较函数(qsort)
复杂声明解析:
// 解读:signal是函数,参数int和void(*)(int),返回void(*)(int)
void (*signal(int sig, void (*handler)(int)))(int);
// 使用typedef简化
typedef void (*SigHandler)(int);
SigHandler signal(int sig, SigHandler handler);
三、对比表格
特征 | 指针函数 | 函数指针 |
---|---|---|
本质 | 返回指针的函数 | 指向函数的指针变量 |
声明重点 | int* func() 星号在返回值位置 |
int (*func_ptr)() 星号在变量名旁 |
内存占用 | 函数代码段 | 指针变量(通常4/8字节) |
典型用途 | 资源创建/获取地址 | 动态调用/回调机制 |
操作权限 | 定义函数逻辑 | 仅能调用指向的函数 |
赋值方式 | 函数返回值自动赋值 | 需显式赋值函数地址 |
四、高级用法示例
- 函数指针数组(命令模式)
void start() { printf("Starting...\n"); }
void stop() { printf("Stopping...\n"); }
void reboot() { printf("Rebooting...\n"); }
int main() {
void (*commands[])() = {start, stop, reboot};
int choice;
printf("Enter command (0-start, 1-stop, 2-reboot): ");
scanf("%d", &choice);
if(choice >=0 && choice <=2) {
commands[choice](); // 动态调用
}
return 0;
}
- 结合结构体(策略模式)
typedef struct {
float (*calc)(float, float); // 计算策略
char symbol; // 运算符
} Operation;
float add(float a, float b) { return a + b; }
float multiply(float a, float b) { return a * b; }
int main() {
Operation ops[] = {
{add, '+'},
{multiply, '*'}
};
for(int i=0; i<2; i++) {
float res = ops[i].calc(3.5, 2);
printf("3.5 %c 2 = %.1f\n", ops[i].symbol, res);
}
return 0;
}
- 回调函数(事件处理)
// 注册回调函数类型
typedef void (*EventCallback)(int event_type);
// 事件处理器
void event_handler(int event) {
printf("Received event: %d\n", event);
}
// 模拟事件触发函数
void trigger_event(EventCallback cb) {
cb(1001); // 触发事件
}
int main() {
trigger_event(event_handler);
return 0;
}
五、核心注意事项
函数指针类型匹配:
int func1(char) {...} void func2(int) {...} int (*fp1)(char) = func1; // 正确 int (*fp2)(int) = func1; // 警告:参数类型不匹配 void (*fp3)(int) = func2; // 正确
现代C的改进:
// C11新增的类型安全写法 int (*fp)(int) = &func; // 显式取地址 int result = (*fp)(10); // 标准调用方式
调试技巧:
printf("Function address: %p\n", (void*)fp); // 打印函数地址
跨平台问题:
// Windows的__stdcall调用约定 typedef int (__stdcall *WinAPIProc)(int);
掌握这两个概念的区分和使用,是理解C语言高级编程(如操作系统开发、驱动程序开发)的关键基础。建议通过实际项目(如实现命令行解析器、设计插件系统等)来加深理解。