【C语言】(10)—指针4

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


前言


提示:以下是本篇文章正文内容,下面案例可供参考

一、回调函数的本质与应用

1.1 什么是回调函数?

回调函数(Callback Function)是通过函数指针调用的函数。其核心思想是:

  • 将函数的指针(地址)作为参数传递给另一个函数

  • 当特定事件或条件发生时,通过这个指针调用对应的函数

  • 被调用的函数称为回调函数

回调函数的定义

回调函数不是由函数的实现方直接调用,而是在特定事件或条件发生时由另一方调用的,用于对该事件或条件进行响应。

1.2 回调函数的典型应用场景

  1. 事件驱动编程(如GUI事件处理)

  2. 排序算法中的比较函数

  3. 异步操作完成时的通知

  4. 通用框架中的可扩展点

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;
}

改造后的优势:

  1. 消除了重复的输入输出代码

  2. 业务逻辑更加清晰

  3. 更容易扩展新的运算功能

二、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 关键点分析

  1. void*指针的使用:实现通用数据类型的处理

  2. 字节级操作:处理未知大小的数据类型

  3. 比较函数的回调:实现自定义排序规则

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 实现细节解析

  1. void*指针

    • 可以指向任意类型的数据

    • 不能直接解引用,必须转换为具体类型指针后才能访问数据

  2. 字节级交换

    • 通过逐字节交换实现任意数据类型的交换

    • char*指针算术运算以1字节为单位,适合通用操作

  3. 元素定位

    • (char*)base + j*size 计算第j个元素的地址

    • size参数确保正确跳过每个元素

  4. 比较函数

    • 返回>0表示第一个参数应排在第二个参数之后

    • 返回<0表示第一个参数应排在第二个参数之前

    • 返回0表示两个参数相等

四、关键知识点总结

  1. 回调函数

    • 通过函数指针实现

    • 将函数作为参数传递

    • 提高代码的模块化和复用性

  2. qsort函数

    • 标准库提供的通用排序函数

    • 依赖于比较回调函数

    • 可以排序任意类型的数据

  3. void*指针

    • 通用指针类型

    • 使用时需要类型转换

    • 是实现通用算法的重要工具

  4. 通用算法实现

    • 通过结合void*和回调函数

    • 需要字节级操作

    • 元素大小信息至关重要

相关推荐
..过云雨14 分钟前
01. Qt介绍及Qt开发环境搭建(2025.05最新官网下载方式)
开发语言·qt
爱吃土豆的马铃薯ㅤㅤㅤㅤㅤㅤㅤㅤㅤ1 小时前
crud方法命名示例
java·开发语言
瓦力wow2 小时前
python 绘制3D平面图
开发语言·python·3d·matplotlib
Cherl.2 小时前
探索数据结构的时间与空间复杂度:编程世界的效率密码
c语言·数据结构·算法·时间复杂度·空间复杂度
Yu_Mao_Cat3 小时前
数独求解器3.0 增加latex格式读取
开发语言·python·算法
ElvInR3 小时前
冒泡排序详解
c语言·c++·排序算法·冒泡排序
天若有情6734 小时前
探秘 C++ 计数器类:从基础实现到高级应用
java·开发语言·c++
进击的愤怒4 小时前
GIM发布新版本了 (附rust CLI制作brew bottle流程)
开发语言·后端·rust
x-cmd4 小时前
x-cmd install | cargo-selector:优雅管理 Rust 项目二进制与示例,开发体验升级
开发语言·后端·rust·cargo·示例