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

C语言指针深入详解(五):回调函数、qsort函数

目录

一、回调函数

1、使用回调函数改造前

2、使用回到函数改造后

二、qsort使用举例 

1、使用qsort函数排序整型数据

2、使用qsort排序结构数据

三、qsort函数模拟实现

结语


🔥个人主页:艾莉丝努力练剑

🍓专栏传送门:《C语言》

🍉学习方向:C/C++方向

⭐️人生格言:为天地立心,为生民立命,为往圣继绝学,为万世开太平


 


前言:前面几篇文章介绍了c语言的一些知识,包括循环、数组、函数、VS实用调试技巧、函数递归、操作符等,在这篇文章中,我将继续介绍指针的一些重要知识点!由于指针的内容较多,博主将会分为六篇博客介绍,这是第五篇啦!对指针感兴趣的友友们可以在评论区一起交流学习! 


一、回调函数

回调函数是什么?回调函数就是一个通过函数指针调用的函数。

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

在我们平常写的计算机的实现的代码中,有些代码是重复出现的,虽说执行计算的逻辑是区别的,但是输入输出操作是冗余的,有没有办法,简化一些呢?

这些重复出现只有调用函数的逻辑是有差异的,要想简化它们,我们可以把调用的函数的地址以参数的形式传递过去,使用函数指针接收,函数指针指向什么函数就调用什么函数,这里其实使用的就是回调函数的功能。

1、使用回调函数改造前

代码实现:

#define  _CRT_SECURE_NO_WARNINGS  1#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;
}int main()
{int x, y;int input = 1;int ret = 0;do{printf("*************************\n");printf(" 1:add 2:sub \n");printf(" 3:mul 4:div \n");printf("*************************\n");printf("请选择:");scanf("%d", &input);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 3:printf("输⼊操作数:");scanf("%d %d", &x,&y);ret = mul(x, y);printf("ret = %d\n",ret);break;case 4:printf("输入操作数:");scanf("%d %d", &x,&y);ret = div(x, y);printf("ret = %d\n",ret);break;case 0:printf("退出程序\n");break;default:printf("选择错误\n");break;}} while (input);return 0;
}

2、使用回调函数改造后

代码实现:

#define  _CRT_SECURE_NO_WARNINGS  1#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 ret = 0;int x, y;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("*************************\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");break;}} while (input);return 0;
}

二、qsort使用举例 

1、使用qsort函数排序整型数据

代码实现:

#define  _CRT_SECURE_NO_WARNINGS  1#include <stdio.h>//qosrt函数的使用者得实现一个比较函数 int int_cmp(const void* p1, const void* p2)
{return (*(int*)p1 - *(int*)p2);
}int main()
{int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };int i = 0;qsort(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;
}

2、使用qsort排序结构数据

代码实现:

#define  _CRT_SECURE_NO_WARNINGS  1struct Stu //学生
{char name[20];//名字 int age;//年龄 
};
//假设按照年龄来比较 
int cmp_stu_by_age(const void* e1, const void* e2)
{return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
//strcmp - 是库函数,是专门用来比较两个字符串的大小的 
//假设按照名字来⽐较 
int cmp_stu_by_name(const void* e1, const void* e2)
{return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}
//按照年龄来排序 
void test2()
{struct Stu s[] = { {"zhangsan", 20}, {"lisi", 30}, {"wangwu", 15} };int sz = sizeof(s) / sizeof(s[0]);qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);
}
//按照名字来排序 
void test3()
{struct Stu s[] = { {"zhangsan", 20}, {"lisi", 30}, {"wangwu", 15} };int sz = sizeof(s) / sizeof(s[0]);qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);
}
int main()
{test2();test3();return 0;
}

三、qsort函数模拟实现

使用回调函数,模拟实现qsort(采用冒泡的方式)。
注意:这里第一次使用void* 的指针,讲解 void* 的作用。

#define  _CRT_SECURE_NO_WARNINGS  1#include <stdio.h>int int_cmp(const void* p1, const void* p2)
{return (*(int*)p1 - *(int*)p2);
}void _swap(void* p1, void* p2, int size)
{int i = 0;for (i = 0; i < size; i++){char tmp = *((char*)p1 + i);*((char*)p1 + i) = *((char*)p2 + i);*((char*)p2 + i) = tmp;}
}void bubble(void* base, int count, int size, int(*cmp)(void*, void*))
{int i = 0;int j = 0;for (i = 0; i < count - 1; i++){for (j = 0; j < count - i - 1; j++){if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0){_swap((char*)base + j * size, (char*)base + (j + 1) * size,size);}}}
}
int main()
{int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };int i = 0;bubble(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;
}

结语

往期回顾:

C语言指针深入详解(一):内存和地址、指针变量和地址、指针变量类型的意义、指针运算

C语言指针深入详解(二):const修饰指针、野指针、assert断言、指针的使用和传址调用

C语言指针深入详解(三):数组名理解、指针访问数组、一维数组传参的本质、冒泡排序、二级指针、指针数组、指针数组模拟二维数组

结语:本篇文章就到此结束了,本文为友友们分享了一些指针相关的重要知识点,如果友友们有补充的话欢迎在评论区留言,下一期我们将继续介绍指针剩下的一些重要知识点,感谢友友们的关注与支持!

http://www.lryc.cn/news/2380595.html

相关文章:

  • 数据结构进阶:AVL树与红黑树
  • 容器化-K8s-镜像仓库使用和应用
  • 基于Spring Boot + Vue的教师工作量管理系统设计与实现
  • 预先学习:构建智能系统的 “未雨绸缪” 之道
  • 完善网络安全等级保护,企业需注意:
  • Trae 04.22版本深度解析:Agent能力升级与MCP市场对复杂任务执行的革新
  • OceanBase 开发者大会:详解 Data × AI 战略,数据库一体化架构再升级
  • 正则表达式进阶(三):递归模式与条件匹配的艺术
  • ubuntu环境下 基于Python 打包的 批量命令行可视化操作工具 GUI
  • docker介绍与常用命令汇总
  • [创业之路-369]:企业战略管理案例分析-9-战略制定-差距分析的案例之华为
  • 谷歌宣布推出 Android 的新安全功能,以防止诈骗和盗窃
  • Qt/C++编写音视频实时通话程序/画中画/设备热插拔/支持本地摄像头和桌面
  • Android trace presentFence屏幕显示的帧
  • Spring是如何实现scope作用域支持
  • Helm Chart 中配置多个 Docker Registry 地址以实现备用访问
  • FreeSWITCH rtcp-mux 测试
  • c++ 类的语法4
  • NMOS和PMOS的区别
  • java云原生实战之graalvm 环境安装
  • 2025年电工杯新规发布-近三年题目以及命题趋势
  • python打卡day30@浙大疏锦行
  • 替换word中的excel
  • 大模型服务如何实现高并发与低延迟
  • 异丙肌苷市场:现状、挑战与未来展望
  • OBS Studio:windows免费开源的直播与录屏软件
  • [ 计算机网络 ] | 宏观谈谈计算机网络
  • 经典面试题:TCP 三次握手、四次挥手详解
  • 高光谱数据处理技术相关
  • 【动态规划】P10988 [蓝桥杯 2023 国 Python A] 走方格|普及+