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

C语言_回调函数和qsort

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 input = 0;int a, b;do {printf("___________________________\n");printf("______1.add     2.sub______\n");printf("______3.mul     4.div______\n");printf("______0.ret          ______\n");scanf("%d", &input);switch (input) {case 1:printf("请输入操作数:\n");scanf("%d %d", &a, &b);printf("%d\n", add(a, b));break;case 2:printf("请输入操作数:\n");scanf("%d %d", &a, &b);printf("%d\n", sub(a, b));break;case 3:printf("请输入操作数:\n");scanf("%d %d", &a, &b);printf("%d\n", mul(a, b));break;case 4:printf("请输入操作数:\n");scanf("%d %d", &a, &b);printf("%d\n", div(a, b));break;case 0:printf("退出程序\n");break;default:printf("选择错误\n");break;}} while (input);return 0;
}

这段代码中我们可以看到,case中的代码除了的调用的函数不同,其他成分总是反复出现,显得特别臃肿。这个时候我们就要使用回调函数了,再看以下改造后的代码:

#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 cal(int(*pf)(int, int)) {int a, b;printf("输入操作数:\n");scanf("%d %d", &a, &b);printf("%d\n", pf(a,b));
}int main() {int input = 0;int a, b;do {printf("___________________________\n");printf("______1.add     2.sub______\n");printf("______3.mul     4.div______\n");printf("______0.ret          ______\n");scanf("%d", &input);switch (input) {case 1:cal(add);break;case 2:cal(sub);break;case 3:cal(mul);break;case 4:cal(div);break;case 0:printf("退出程序\n");break;default:printf("选择错误\n");break;}} while (input);return 0;
}

这段代码看起来是不是让人眼前一亮呢?将每个case中冗余的部分汇总到一个函数中,再通过函数指针调用所需要的函数。这就是回调函数的作用之一。

2. qsort函数

qsort函数是一个C标准库中的一个通用排序函数,用于对数组进行快速排序。

qsort函数的原型定义在<stdlib.h>头文件中。

下面是qsort函数调用的形式:

void qsort(void *base, size_t nmemb, size_t size,int (*cmp)(const void *, const void *));

函数参数解析:

  • void *base:指向要排序数组首元素的指针。
  • size_t nmemb:数组中元素个数。
  • size_t size:数组中元素的类型大小。
  • int (\*cmp)(const void*,const void*):函数指针,指向比较两个元素的函数。(第一个元素小于第二个元素,返回负整数;两个元素相等,返回零;第一个元素大于第二个元素,返回正整数)。

2.1 qsort的使用

排序整形数据

#include<stdio.h>
#include<stdlib.h>
//要使用qsort函数需先实现一个比较函数
int int_cmp(const void* p1, const void* p2) {return (*(int*)p1 - *(int*)p2);
}int main() {int i = 0;int arr[10] = { 9,2,1,6,5,4,7,8,0,3 };qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(arr[0]), *int_cmp);for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) {printf("%d\t", arr[i]);}return 0;
}

排序结构数据

#include<stdio.h>
#include<stdlib.h>
struct stu {char name[20];//名字int age;//年龄
};//比较名字
int cmp_name(const void* p1, const void* p2) {return strcmp(((struct stu*)p1)->name,((struct stu*)p2)->name);//strcmp 是一个库函数,专门用来比较两个字符串大小
}
//比较年龄
int cmp_age(const void* p1, const void* p2) {return ((struct stu*)p1)->age - ((struct stu*)p2)->age;
}//排序名字
void test1() {struct stu s[] = { {"wu",22},{"liu",20}, {"qi",18} };qsort(s, sizeof(s) / sizeof(s[0]), sizeof(s[0]), *cmp_name);
}
//排序年龄
void test2() {struct stu s[] = { {"wu",22},{"liu",20}, {"qi",18} };qsort(s, sizeof(s) / sizeof(s[0]), sizeof(s[0]), *cmp_age);
}int main() {test1();test2();return 0;
}

2.2 qsort的模拟实现

使用回调函数,用冒泡排序的方式模拟实现qsort

#include<stdio.h>
#include<stdlib.h>
//比较函数
int int_cmp(const void* p1, const void* p2) {//使用const修饰指针,增强代码的可维护性。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, j;for (i = 0; i < count - 1; i++) {for (j = 0; j < count - 1 - i; 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[10] = { 66,23,22,1,3,5,7,9,10,2 };bubble(arr, sizeof(arr) / sizeof(arr[0]), sizeof(arr[0]), *int_cmp);int i;for (i = 0; i < 10; i++) {printf("%d\t", arr[i]);}return 0;
}

相关文章:

  • MATLAB中的艺术:用爱心形状控制坐标轴
  • git 清除二进制文件的 changes 状态
  • JBOSS中间件漏洞复现
  • 多维时序 | GWO-VMD-SSA-LSTM灰狼优化变分模态分解联合麻雀优化长短期记忆网络多变量时间序列光伏功率预测(Matlab)
  • 迈巴赫 S480 的奢华升级之旅头等舱行政独立 4 座
  • 电影《749局》酷燃首映 苗苗神秘感大片释出氛围感拉满
  • 有关若依登录过程前端的对应处理学习
  • 第L2周:机器学习|线性回归模型 LinearRegression:2. 多元线性回归模型
  • FileLink跨网文件交换|解决网络隔离导致的文件共享难题
  • Unity NetCode 客户端连接不上服务器,局域网模式 Failed to connect to server.
  • 贴片式TF卡(SD NAND)参考设计
  • 采用云端SaaS服务模式的基层云HIS系统,源码开放合作,B/S架构,公立二甲医院应用五年。
  • 828华为云征文 | 华为云Flexus X实例在混合云环境中的应用与实践
  • 04 B-树
  • 使用 npkill 快速清理本地 node_modules 文件
  • 分享的文章《人生如棋》
  • “Material Design”设计规范在 ComponentOne For WinForm 的全新尝试!
  • 2017 前端面试准备 - 收藏集 - 掘金
  • AHK 中 = 和 == 等比较运算符的用法
  • Linux后台研发超实用命令总结
  • oldjun 检测网站的经验
  • open-falcon 开发笔记(一):从零开始搭建虚拟服务器和监测环境
  • Python进阶细节
  • Redis提升并发能力 | 从0开始构建SpringCloud微服务(2)
  • Service Worker
  • underscore源码剖析之整体架构
  • 飞驰在Mesos的涡轮引擎上
  • 工作手记之html2canvas使用概述
  • 聊聊flink的TableFactory
  • 数据库写操作弃用“SELECT ... FOR UPDATE”解决方案
  • 思维导图—你不知道的JavaScript中卷
  • 微信开源mars源码分析1—上层samples分析
  • 译自由幺半群
  • 回归生活:清理微信公众号
  • ​直流电和交流电有什么区别为什么这个时候又要变成直流电呢?交流转换到直流(整流器)直流变交流(逆变器)​
  • # 睡眠3秒_床上这样睡觉的人,睡眠质量多半不好
  • #传输# #传输数据判断#
  • $HTTP_POST_VARS['']和$_POST['']的区别
  • (C++20) consteval立即函数
  • (void) (_x == _y)的作用
  • (笔记)第三期书生·浦语大模型实战营(十一卷王场)--书生入门岛通关第1关Linux 基础知识
  • (三) prometheus + grafana + alertmanager 配置Redis监控
  • (原創) 人會胖會瘦,都是自我要求的結果 (日記)
  • (转)利用ant在Mac 下自动化打包签名Android程序
  • **PHP分步表单提交思路(分页表单提交)
  • .env.development、.env.production、.env.staging
  • .NET 5种线程安全集合
  • .NET Compact Framework 3.5 支持 WCF 的子集
  • .NET core 自定义过滤器 Filter 实现webapi RestFul 统一接口数据返回格式
  • .NET MVC、 WebAPI、 WebService【ws】、NVVM、WCF、Remoting
  • .NET 材料检测系统崩溃分析
  • .NET 简介:跨平台、开源、高性能的开发平台
  • .NET 中各种混淆(Obfuscation)的含义、原理、实际效果和不同级别的差异(使用 SmartAssembly)
  • .NET设计模式(2):单件模式(Singleton Pattern)
  • @private @protected @public