提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
提示:以下是本篇文章正文内容,下面案例可供参考
一、回调函数的本质与应用
1.1 什么是回调函数?
回调函数(Callback Function)是通过函数指针调用的函数。其核心思想是:
-
将函数的指针(地址)作为参数传递给另一个函数
-
当特定事件或条件发生时,通过这个指针调用对应的函数
-
被调用的函数称为回调函数
回调函数的定义 :
回调函数不是由函数的实现方直接调用,而是在特定事件或条件发生时由另一方调用的,用于对该事件或条件进行响应。
1.2 回调函数的典型应用场景
-
事件驱动编程(如GUI事件处理)
-
排序算法中的比较函数
-
异步操作完成时的通知
-
通用框架中的可扩展点
1.3 回调函数示例:改造计算器程序
原始计算器代码存在大量重复的输入输出逻辑:
// 改造前的代码片段
switch(input) {
case 1:
printf("输入操作数:");
scanf("%d %d", &x, &y);
ret = add(x, y);
printf("ret = %d\n", ret);
break;
case 2:
printf("输入操作数:");
scanf("%d %d", &x, &y);
ret = sub(x, y);
printf("ret = %d\n", ret);
break;
// ...更多case...
}
使用回调函数改造后:
cpp
#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 a / b; }
void calc(int (*pf)(int, int)) {
int x, y, ret;
printf("输入操作数:");
scanf("%d %d", &x, &y);
ret = pf(x, y);
printf("ret = %d\n", ret);
}
int main() {
int input = 1;
do {
printf("******************\n");
printf("1:add 2:sub\n");
printf("3:mul 4:div\n");
printf("0:exit\n");
printf("******************\n");
printf("请选择:");
scanf("%d", &input);
switch(input) {
case 1: calc(add); break;
case 2: calc(sub); break;
case 3: calc(mul); break;
case 4: calc(div); break;
case 0: printf("退出程序\n"); break;
default: printf("选择错误\n");
}
} while(input);
return 0;
}
改造后的优势:
-
消除了重复的输入输出代码
-
业务逻辑更加清晰
-
更容易扩展新的运算功能
二、qsort函数深度解析
2.1 qsort函数原型
cpp
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
参数说明:
-
base
:待排序数组的起始地址 -
nmemb
:数组元素个数 -
size
:每个元素的大小(字节) -
compar
:比较函数的指针
三、模拟实现qsort函数
为了更好地理解qsort的工作原理,我们可以基于冒泡排序算法模拟实现一个类似的通用排序函数。
3.1 关键点分析
-
void*指针的使用:实现通用数据类型的处理
-
字节级操作:处理未知大小的数据类型
-
比较函数的回调:实现自定义排序规则
3.2 完整实现代码
cpp
#include <stdio.h>
#include <string.h>
// 比较整型的回调函数
int int_cmp(const void *p1, const void *p2) {
return (*(int*)p1 - *(int*)p2);
}
// 交换两个元素(字节级操作)
void _swap(void *p1, void *p2, int size) {
for(int i=0; i<size; i++) {
char tmp = *((char*)p1 + i);
*((char*)p1 + i) = *((char*)p2 + i);
*((char*)p2 + i) = tmp;
}
}
// 模拟的qsort实现(基于冒泡排序)
void bubble_sort(void *base, int count, int size,
int (*cmp)(const void*, const void*)) {
for(int i=0; i<count-1; i++) {
for(int j=0; j<count-i-1; j++) {
void *elem1 = (char*)base + j*size;
void *elem2 = (char*)base + (j+1)*size;
if(cmp(elem1, elem2) > 0) {
_swap(elem1, elem2, size);
}
}
}
}
int main() {
int arr[] = {1, 3, 5, 7, 9, 2, 4, 6, 8, 0};
int i = 0;
bubble_sort(arr, sizeof(arr)/sizeof(arr[0]), sizeof(int), int_cmp);
for(i=0; i<sizeof(arr)/sizeof(arr[0]); i++) {
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
3.3 实现细节解析
-
void*指针:
-
可以指向任意类型的数据
-
不能直接解引用,必须转换为具体类型指针后才能访问数据
-
-
字节级交换:
-
通过逐字节交换实现任意数据类型的交换
-
char*
指针算术运算以1字节为单位,适合通用操作
-
-
元素定位:
-
(char*)base + j*size
计算第j个元素的地址 -
size
参数确保正确跳过每个元素
-
-
比较函数:
-
返回>0表示第一个参数应排在第二个参数之后
-
返回<0表示第一个参数应排在第二个参数之前
-
返回0表示两个参数相等
-
四、关键知识点总结
-
回调函数:
-
通过函数指针实现
-
将函数作为参数传递
-
提高代码的模块化和复用性
-
-
qsort函数:
-
标准库提供的通用排序函数
-
依赖于比较回调函数
-
可以排序任意类型的数据
-
-
void*指针:
-
通用指针类型
-
使用时需要类型转换
-
是实现通用算法的重要工具
-
-
通用算法实现:
-
通过结合void*和回调函数
-
需要字节级操作
-
元素大小信息至关重要
-