外观
05.回调函数详解
约 1761 字大约 6 分钟
算法C滤波算法个人
2025-12-12
什么是回调函数?
回调函数(Callback Function) 是一种通过函数指针调用的函数。它允许我们将一个函数作为参数传递给另一个函数,并在需要的时候由接收函数调用这个传递进来的函数。
基本概念
函数指针
要理解回调函数,首先需要了解函数指针:
// 函数原型
int add(int a, int b);
// 函数指针声明
int (*func_ptr)(int, int);
// 赋值
func_ptr = add;
// 通过函数指针调用
int result = func_ptr(3, 4);回调函数的基本形式
// 回调函数类型定义
typedef void (*Callback)(int);
// 接收回调函数作为参数的函数
void process_numbers(int array[], int size, Callback callback) {
for (int i = 0; i < size; i++) {
callback(array[i]); // 调用回调函数
}
}
// 实际的回调函数
void print_number(int num) {
printf("Number: %d\n", num);
}
// 使用
int main() {
int numbers[] = {1, 2, 3, 4, 5};
process_numbers(numbers, 5, print_number);
return 0;
}回调函数的优势
- 增加代码灵活性:可以在不修改原函数的情况下改变其行为
- 实现抽象和通用性:编写更通用的函数,具体行为由回调决定
- 事件驱动编程:非常适合GUI、网络编程等事件驱动场景
- 异步处理:用于异步操作完成时的通知
实际应用示例
示例1:排序算法中的比较函数
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 比较函数类型定义
typedef int (*CompareFunc)(const void*, const void*);
// 通用排序函数
void sort_array(void *array, size_t count, size_t size, CompareFunc compare) {
// 这里简化实现,实际可使用qsort
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) {
// 交换元素
char temp[size];
memcpy(temp, a, size);
memcpy(a, b, size);
memcpy(b, temp, size);
}
}
}
}
// 比较整数的回调函数
int compare_int(const void *a, const void *b) {
return *(int*)a - *(int*)b;
}
// 比较字符串的回调函数
int compare_string(const void *a, const void *b) {
return strcmp(*(const char**)a, *(const char**)b);
}
int main() {
// 排序整数数组
int numbers[] = {5, 2, 8, 1, 9};
sort_array(numbers, 5, sizeof(int), compare_int);
printf("Sorted numbers: ");
for (int i = 0; i < 5; i++) {
printf("%d ", numbers[i]);
}
printf("\n");
// 排序字符串数组
const char *names[] = {"Alice", "Bob", "Charlie", "David"};
sort_array(names, 4, sizeof(char*), compare_string);
printf("Sorted names: ");
for (int i = 0; i < 4; i++) {
printf("%s ", names[i]);
}
printf("\n");
return 0;
}示例2:事件处理系统
#include <stdio.h>
#include <stdlib.h>
// 事件类型
typedef enum {
EVENT_CLICK,
EVENT_KEYPRESS,
EVENT_TIMER
} EventType;
// 事件结构
typedef struct {
EventType type;
int data;
} Event;
// 事件处理器回调类型
typedef void (*EventHandler)(Event);
// 事件处理器结构
typedef struct {
EventType type;
EventHandler handler;
} EventListener;
// 简单的事件系统
typedef struct {
EventListener *listeners;
int count;
int capacity;
} EventSystem;
// 初始化事件系统
void init_event_system(EventSystem *sys, int capacity) {
sys->listeners = malloc(sizeof(EventListener) * capacity);
sys->count = 0;
sys->capacity = capacity;
}
// 注册事件监听器
void register_listener(EventSystem *sys, EventType type, EventHandler handler) {
if (sys->count < sys->capacity) {
sys->listeners[sys->count].type = type;
sys->listeners[sys->count].handler = handler;
sys->count++;
}
}
// 触发事件
void trigger_event(EventSystem *sys, Event event) {
for (int i = 0; i < sys->count; i++) {
if (sys->listeners[i].type == event.type) {
sys->listeners[i].handler(event);
}
}
}
// 各种事件处理器(回调函数)
void handle_click(Event event) {
printf("Click event handled. Data: %d\n", event.data);
}
void handle_keypress(Event event) {
printf("Keypress event handled. Key code: %d\n", event.data);
}
void handle_timer(Event event) {
printf("Timer event handled. Tick count: %d\n", event.data);
}
int main() {
EventSystem sys;
init_event_system(&sys, 10);
// 注册事件处理器
register_listener(&sys, EVENT_CLICK, handle_click);
register_listener(&sys, EVENT_KEYPRESS, handle_keypress);
register_listener(&sys, EVENT_TIMER, handle_timer);
// 触发事件
trigger_event(&sys, (Event){EVENT_CLICK, 100});
trigger_event(&sys, (Event){EVENT_KEYPRESS, 65}); // 'A'键
trigger_event(&sys, (Event){EVENT_TIMER, 1000});
free(sys.listeners);
return 0;
}示例3:遍历数组并处理元素
#include <stdio.h>
// 定义回调函数类型
typedef void (*ProcessFunc)(int, void*);
// 通用遍历函数
void foreach_element(int array[], int size, ProcessFunc process, void *context) {
for (int i = 0; i < size; i++) {
process(array[i], context);
}
}
// 累加器回调函数
void sum_callback(int value, void *context) {
int *sum = (int*)context;
*sum += value;
}
// 最大值查找回调函数
void max_callback(int value, void *context) {
int *max = (int*)context;
if (value > *max) {
*max = value;
}
}
// 收集满足条件的元素回调函数
void filter_callback(int value, void *context) {
struct {
int *result;
int count;
int threshold;
} *filter = context;
if (value > filter->threshold) {
filter->result[filter->count] = value;
filter->count++;
}
}
int main() {
int numbers[] = {1, 5, 3, 8, 2, 9, 4};
int size = sizeof(numbers) / sizeof(numbers[0]);
// 计算总和
int sum = 0;
foreach_element(numbers, size, sum_callback, &sum);
printf("Sum: %d\n", sum);
// 查找最大值
int max = numbers[0];
foreach_element(numbers, size, max_callback, &max);
printf("Max: %d\n", max);
// 筛选大于5的元素
int filtered[10];
struct {
int *result;
int count;
int threshold;
} filter_context = {filtered, 0, 5};
foreach_element(numbers, size, filter_callback, &filter_context);
printf("Numbers greater than 5: ");
for (int i = 0; i < filter_context.count; i++) {
printf("%d ", filtered[i]);
}
printf("\n");
return 0;
}回调函数的注意事项
1. 类型安全
确保回调函数的签名与函数指针类型完全匹配,否则会导致未定义行为。
2. NULL指针检查
在调用回调函数前,应检查函数指针是否为NULL:
void process_with_callback(int data, void (*callback)(int)) {
if (callback != NULL) {
callback(data);
} else {
// 默认处理
printf("Default processing: %d\n", data);
}
}3. 上下文数据传递
如果需要传递额外的数据给回调函数,可以使用void指针:
typedef void (*CallbackWithContext)(int, void*);
void process(int value, CallbackWithContext callback, void *context) {
callback(value, context);
}4. 状态保持
如果回调函数需要保持状态,可以使用静态变量或通过上下文参数传递:
// 使用静态变量(线程不安全)
void callback_with_state(int value) {
static int count = 0;
count++;
printf("Call #%d: %d\n", count, value);
}
// 通过上下文传递状态
struct CallbackState {
int count;
int total;
};
void callback_with_context(int value, void *context) {
struct CallbackState *state = (struct CallbackState*)context;
state->count++;
state->total += value;
}高级应用:函数指针数组
#include <stdio.h>
// 定义操作函数类型
typedef int (*Operation)(int, int);
// 各种操作函数
int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }
int multiply(int a, int b) { return a * b; }
int divide(int a, int b) { return b != 0 ? a / b : 0; }
// 操作函数数组
Operation operations[] = {add, subtract, multiply, divide};
const char *operation_names[] = {"Add", "Subtract", "Multiply", "Divide"};
int main() {
int a = 10, b = 5;
for (int i = 0; i < 4; i++) {
int result = operations[i](a, b);
printf("%s: %d %s %d = %d\n",
operation_names[i], a,
i == 0 ? "+" : i == 1 ? "-" : i == 2 ? "*" : "/",
b, result);
}
return 0;
}总结
回调函数是C语言中强大的编程技术,它提供了一种灵活的方式来定制函数行为。通过函数指针,我们可以:
- 实现通用算法:如排序、搜索、遍历等
- 创建事件驱动系统:如GUI、网络编程
- 实现插件架构:允许动态加载和调用函数
- 简化异步编程:处理异步操作完成后的回调
