1. 函数指针:C语言的瑞士军刀
在C语言的世界里,指针就像一把万能钥匙,而函数指针则是这把钥匙上最精巧的工具。我第一次接触函数指针是在大学时期,当时为了理解这个概念整整花了两周时间。但一旦掌握后,它彻底改变了我编写C代码的方式。
函数指针本质上是一个变量,只不过它存储的不是数据,而是函数的入口地址。这种间接调用的特性,为C语言带来了惊人的灵活性。想象一下,你可以像传递整数一样传递"行为",这种能力在构建复杂系统时尤为珍贵。
1.1 函数指针的声明艺术
声明函数指针时,那个看似复杂的语法其实有规律可循。让我们拆解一个典型声明:
c复制int (*compare)(const void *, const void *);
这个声明可以这样理解:
(*compare):compare是一个指针(const void *, const void *):指向一个接受两个void指针参数的函数int:该函数返回整型值
专业提示:使用typedef可以大幅提高代码可读性。例如:
c复制typedef int (*CompareFunc)(const void *, const void *); CompareFunc compare;
我在实际项目中见过太多因为函数指针声明错误导致的bug。最常见的错误是忘记括号,比如写成int *compare(const void *, const void *),这就变成了一个返回int指针的函数声明,而非函数指针。
1.2 函数指针的实战应用
让我们看一个更贴近实际的例子——实现一个通用的排序函数:
c复制void sort(void *array, size_t count, size_t size,
int (*compare)(const void *, const void *)) {
for (size_t i = 0; i < count-1; i++) {
for (size_t j = 0; j < count-i-1; j++) {
void *a = (char *)array + j*size;
void *b = (char *)array + (j+1)*size;
if (compare(a, b) > 0) {
swap(a, b, size);
}
}
}
}
这个排序函数可以处理任何类型的数组,只要提供相应的比较函数。比如对整数数组排序:
c复制int compare_int(const void *a, const void *b) {
return *(int *)a - *(int *)b;
}
int main() {
int nums[] = {3,1,4,1,5,9,2,6};
sort(nums, sizeof(nums)/sizeof(int), sizeof(int), compare_int);
// 现在nums是有序的了
}
这种设计模式在标准库中随处可见,比如qsort函数。它的强大之处在于将算法与数据类型解耦,实现了真正的代码复用。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 回调函数:C语言的插件系统
如果说函数指针是工具,那么回调函数就是使用这些工具的蓝图。我第一次真正体会到回调函数的威力是在开发一个网络爬虫时,通过回调机制实现了可扩展的页面解析逻辑。
2.1 回调函数的本质
回调函数的核心思想是"你告诉我怎么做,我来决定什么时候做"。这种控制反转(IoC)的模式在现代软件架构中无处不在。在C语言中,我们通过函数指针实现这种模式。
一个典型的回调场景是事件处理。比如在GUI编程中:
c复制typedef void (*ClickHandler)(int x, int y);
struct Button {
int x, y, width, height;
ClickHandler onClick;
};
void register_click_handler(struct Button *btn, ClickHandler handler) {
btn->onClick = handler;
}
void button_click(struct Button *btn, int mouseX, int mouseY) {
if (mouseX >= btn->x && mouseX < btn->x + btn->width &&
mouseY >= btn->y && mouseY < btn->y + btn->height) {
if (btn->onClick) {
btn->onClick(mouseX, mouseY);
}
}
}
用户代码可以这样使用:
c复制void my_click_handler(int x, int y)
