当前位置: 首页 > news >正文

深入理解指针5

1.回调函数是什么

回调函数就是⼀个通过函数指针调⽤的函数。 如果你把函数的指针(地址)作为参数传递给另⼀个函数,当这个指针被⽤来调⽤其所指向的函数 时,被调⽤的函数就是回调函数。回调函数不是由该函数的实现⽅直接调⽤,⽽是在特定的事件或条 件发⽣时由另外的⼀⽅调⽤的,⽤于对该事件或条件进⾏响应。

上一篇博客中写了一个简易的计算器

int Add(int x, int y) { return x + y; } int Sub(int x, int y) { return x - y; } int Mul(int x, int y) { return x * y; } int Div(int x, int y) { return x / y; } void menu() { printf("-------------------------------\n"); printf("----- 1. add 2. sub -----\n"); printf("----- 3. mul 4. div -----\n"); printf("----- 0. exit -----\n"); printf("-------------------------------\n"); } void calc(int (*pf)(int, int)) { int x = 0; int y = 0; int r = 0; printf("请输入2个操作数:"); scanf("%d%d", &x, &y); r = pf(x, y); printf("结果是: %d\n", r); } int main() { int input = 0; do { menu(); 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("输入错误,请输入0~4的值\n"); break; } } while (input); return 0; }

这里int (*pf)(int, int)作为calc函数的参数,说白了回调函数就是将函数的地址作为新函数的参数,以达到进行调用的目的,通常可起到简化代码量的作用。

2. qsort

qsort函数原型

void qsort (void* base, size_t num, size_t size,int (*compar)(const void*,const void*))

qsort是基于快速排序实现,可排序任意类型的数据

1.void*指向数组中第一个要排序的对象,转换为void*

2.size_t num数组中按基数指向的元素数。

3.size_t size数组中每个元素的字节大小。

4.int (*compar)(const void*,const void*) (函数指针)指向一个比较两个元素的函数。

其中comp函数的规则如下

返回值含义
<0p1指向的元素小于p2指向的元素
>0p1指向的元素大于p2指向的元素
=0p1指向的元素等于p2指向的元素

由此我们可得到以下代码(需包含stdlib.h )

int comp(const void* p1, const void* p2)//void*无法解引用,需要强制转换为int*类型 { //if (*(int*)p1 < *(int*)p2) // return -1; //else if (*(int*)p1 > *(int*)p2) // return 1; //else // return 0; return(*(int*)p1 - *(int*)p2); } int main() { int arr[10] = { 9,8,7,6,5,4,3,2,1,0 }; int len = sizeof(arr) / sizeof(arr[0]); int size = sizeof(int); qsort(arr,len,size,comp); for (int i = 0; i < 10; i++) { printf("%d ", *(arr + i)); } return 0; }

如果想要降序排列

return(*(int*)p2 - *(int*)p1);

也可对结构体排序

struct Stu { char name[20]; int age; }; int cmp_age(const void* p1,const void* p2)//年龄升序 { return (*(struct Stu*)p1).age - (*(struct Stu*)p2).age; } int main() { struct Stu arr[] = { {"zhangsan",18},{"lisi",25},{"wangwu",15} }; int sz = sizeof(arr) / sizeof(arr[0]); qsort(arr, sz, sizeof(arr[0]), cmp_age); for (int i = 0; i < sz; i++) { printf("%d ", arr[i].age); } return 0; }

还可通过name进行排序,等后面介绍strcmp函数后再实现。关于结构体其他的知识后面也会写博客介绍

3. qsort函数的模拟实现

使⽤回调函数,模拟实现qsort(采⽤冒泡的⽅式)

首先给出冒泡排序的基础代码

void bubble_sort(int* arr, int sz) { int flag = 1; for (int i = 0; i < sz - 1; i++) { for (int j = 0; j < sz - i - 1; j++) { if (arr[j] > arr[j + 1]) { int tmp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = tmp; flag = 0; } } if (flag) return; } }

仿造sqsort给出函数原型

void my_qsort(void* base, size_t len, size_t size, int(*cmp)(const void* p1, const void* p2))

主体还是两个for循环来控制排序的次数

for (int i = 0; i < len - 1; i++) { for (int j = 0; j < len - i - 1; j++) { ....... } } }

下面是否进行该次排序的条件可通过comp函数实现

int comp(const void* p1, const void* p2) { return *(int*)p1 - *(int*)p2; }

冒泡排序的交换可通过swap函数实现

void swap(char* buf1, char* buf2, size_t size) { for (int i = 0; i < size; i++) { char tmp = *buf1; *buf1 = *buf2; *buf2 = tmp; buf1++; buf2++; } }

注意由于这里是char* 类型的指针,所以交换时只能一个字节一个字节的进行交换,看图

完整代码如下

int comp(const void* p1, const void* p2) { return *(int*)p1 - *(int*)p2; } void swap(char* buf1, char* buf2, size_t size) { for (int i = 0; i < size; i++) { char tmp = *buf1; *buf1 = *buf2; *buf2 = tmp; buf1++; buf2++; } } void my_qsort(void* base, size_t len, size_t size, int(*cmp)(const void* p1, const void* p2)) { for (int i = 0; i < len - 1; i++) { for (int j = 0; j < len - i - 1; j++) { if (cmp((char*)base + j * size, (char*)base + j * size + 1)) { swap((char*)base + j * size, (char*)base + (j + 1) * size, size); } } } }

这段代码只是为了帮我们理解qsort函数,实际操作直接使用qsort函数即可

http://www.jsqmd.com/news/882597/

相关文章:

  • 2026苏州黄金 铂金 白银 彩金回收口碑榜出炉:这五家店稳居前列,靠谱又放心 - 前途无量YY
  • 深入理解 ARMv7-A|异常/中断处理
  • 猫抓浏览器扩展:构建高效流媒体资源嗅探工作流的终极指南
  • Frida安卓逆向实战:从动态插桩到Native层Hook
  • 荣耀出征手游官网下载:奇迹MU最新官方22区5月30日13点火爆开区!!
  • 前缀和——高频考点:子数组和、区间和、和为 K 的子数组
  • 海工塔吊租赁选购指南:靠谱的高前景、高防辐射公司推荐 - mypinpai
  • 2026宿迁黄金 铂金 白银 彩金回收口碑榜出炉:这五家店稳居前列,靠谱又放心 - 前途无量YY
  • 告别分区焦虑:用GParted Live USB无损调整Ubuntu/Debian分区(附swapfile替代方案)
  • 告别黄牛票!5分钟配置大麦网自动化抢票神器
  • 2026宿州黄金 铂金 白银 彩金回收口碑榜出炉:这五家店稳居前列,靠谱又放心 - 前途无量YY
  • 从ACPI _SUN到物理槽位:深入Linux内核看PCIe插槽编号的诞生与管理
  • 周报5.24
  • 突破物理限制:用ParsecVDisplay在Windows上创建完美虚拟显示器
  • 飞书文档批量导出架构解析:如何设计一个企业级文档迁移工具
  • Tflite模型缓存优化与Arm Ethos-N78 NPU部署实践
  • 如何快速重置JetBrains IDE试用期:高效实用的完整解决方案
  • 2026随州黄金 铂金 白银 彩金回收口碑榜出炉:这五家店稳居前列,靠谱又放心 - 前途无量YY
  • BepInEx终极指南:如何快速上手Unity游戏插件框架的10个技巧
  • NS-USBLoader:Switch文件传输与RCM注入的一站式解决方案
  • 超详细AttentionTransformer:从原理到完整架构全覆盖
  • 3个步骤解锁QQ音乐加密文件:QMCDecode如何让你的音乐库重获自由?
  • 2026陇南黄金 铂金 白银 彩金回收口碑榜出炉:这五家店稳居前列,靠谱又放心 - 前途无量YY
  • 新书上架 | 黄仁勋是如何提前十年押注AI,助推英伟达登顶世界之巅的?
  • 终极免费方案:3分钟解决游戏按键冲突,让操作精度提升87%
  • 2026遂宁黄金 铂金 白银 彩金回收口碑榜出炉:这五家店稳居前列,靠谱又放心 - 前途无量YY
  • 老iMAC焕新记:不拆机不折腾,用三星T7移动固态硬盘让2015款iMac再战五年
  • UE5材质实例MI保姆级指南:如何像调PS滑块一样,实时调整游戏里的砖墙颜色和质感?
  • 别急着买云服务器!手把手教你将闲置Win10台式机改造成SSH远程开发机(保姆级教程)
  • 2026金华黄金 铂金 白银 彩金回收口碑榜出炉:这五家店稳居前列,靠谱又放心 - 前途无量YY