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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/55063.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Docker安装mysql8并配置主从复制

1. 安装mysql8 1.1 新增挂载文件 # 新增mysql挂载文件夹 mkdir -p /root/docker/mysql/m01/log mkdir -p /root/docker/mysql/m01/data mkdir -p /root/docker/mysql/m01/conf1.2 新增mysql配置文件 # 新增mysql配置文件 cd /root/docker/mysql/m01/conf vim my.cnf # 下面是…

关于git分支冲突问题

什么是冲突 在Git中&#xff0c;冲突是指两个或多个开发者对同一文件统一部份进行了不同的修改&#xff0c;并且在合并这些修改时&#xff0c;Git无法自动确定应该采用哪种修改而产生的情况。 分支冲突 如何出现并解决 在一个版本时&#xff0c;有一个master分支&#xff0c…

如何使用WinRAR锁定压缩文件,防止文件被修改或删除?

在日常工作中&#xff0c;我们经常需要分享压缩文件&#xff0c;但也可能面临文件被修改或删除的风险。想要保护压缩文件的完整性&#xff0c;不妨使用WinRAR提供的“锁定压缩文件”功能。这个功能可以防止文件被意外更改或删除&#xff0c;确保压缩文件保持原样。下面一起来看…

Linux中的 `vi` 与 `vim` 使用详解

文章目录 Linux中的 vi 与 vim 使用详解1. vi 编辑器1.1 什么是 vi1.2 vi 的基本用法1.2.1 启动 vi1.2.2 模式1.2.3 基本操作1.2.4 常用命令 1.3 vi 的特点 2. vim 编辑器2.1 什么是 vim2.2 vim 的基本用法2.2.1 启动 vim2.2.2 模式2.2.3 vim 的增强功能2.2.4 vim 的基本操作 2…

如何选择合适的量化交易策略,回测与模拟交易的实战演练

炒股自动化&#xff1a;申请官方API接口&#xff0c;散户也可以 python炒股自动化&#xff08;0&#xff09;&#xff0c;申请券商API接口 python炒股自动化&#xff08;1&#xff09;&#xff0c;量化交易接口区别 Python炒股自动化&#xff08;2&#xff09;&#xff1a;获取…

解决跨域问题的案列

JSONP&#xff08;JSON with Padding&#xff09; JSONP 是一种通过 <script> 标签的跨域请求方法&#xff0c;它依赖于服务器支持并返回特定格式的响应。 示例&#xff1a; 前端&#xff1a; <script> function jsonpCallback(data) {console.log(Received data:…

websocket初识

WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议。WebSocket 使得客户端和服务器之间的数据交换变得更加简单&#xff0c;允许服务端主动向客户端推送数据。在 WebSocket API 中&#xff0c;浏览器和服务器只需要完成一次握手&#xff0c;两者之间就直接可以创建持久性…

【Android 14源码分析】Activity启动流程-1

忽然有一天&#xff0c;我想要做一件事&#xff1a;去代码中去验证那些曾经被“灌输”的理论。                                                                                  – 服装…

Llama 3.2:利用开放、可定制的模型实现边缘人工智能和视觉革命

在我们发布 Llama 3.1 模型群后的两个月内&#xff0c;包括 405B - 第一个开放的前沿级人工智能模型在内&#xff0c;它们所产生的影响令我们兴奋不已。 虽然这些模型非常强大&#xff0c;但我们也认识到&#xff0c;使用它们进行构建需要大量的计算资源和专业知识。 我们也听到…

Meta首款多模态Llama 3.2开源:支持图像推理,还有可在手机上运行的版本 | LeetTalk Daily...

“LeetTalk Daily”&#xff0c;每日科技前沿&#xff0c;由LeetTools AI精心筛选&#xff0c;为您带来最新鲜、最具洞察力的科技新闻。 Meta最近推出的Llama Stack的发布标志着一个重要的里程碑。这一新技术的推出不仅为开发者提供了强大的多模态能力&#xff0c;还为企业和初…

编程题 7-15 计算圆周率【PAT】

文章目录 题目输入格式输出格式输入样例输出样例 题解解题思路完整代码 编程练习题目集目录 题目 根据下面关系式&#xff0c;求圆周率的值&#xff0c;直到最后一项的值小于给定阈值。 2 π 1 1 3 2 ! 3 5 3 ! 3 5 7 ​ n ! ​ 3 5 7 ⋯ ( 2 n 1 ) ⋯ {\frac 2…

安卓13设置删除网络和互联网选项 android13隐藏设置删除网络和互联网选项

总纲 android13 rom 开发总纲说明 文章目录 1.前言2.问题分析3.代码分析4.代码修改4.1修改方法14.2修改方法25.编译6.彩蛋1.前言 有些客户不想让用户修改默认的网络配置,禁止用户进入里面调整网络相关的配置。 2.问题分析 像这个问题,我们有好几种方法去处理,这种需求一般…

IDEA Dependency Analyzer 分析 maven 项目包的依赖

一、场景分析 javax.validation 是我们 SpringMVC 常用的数据校验框架。但是 javax.validation 是一个规范&#xff08;Java Bean Validation&#xff0c;简称 JSR 380&#xff09;&#xff0c;它并没有具体的实现&#xff0c;它的常用实现&#xff0c;是hibernate-validator。…

java技能

日志实际使用 log.error(“111”,e);和 System.out.println(ExceptionUtils.getStackTrace(error)); 日志查询 tail -f root.log 前端页面命名&#xff1a; mounted(){ document.title‘设备可视页面’ } 查看ips所属mac nbtstat -a 10.87.236.60 获取容器名称 hostName In…

POW 与 POS是什么?

POW 与 POS是什么? POW(Proof of Work)和POS(Proof of Stake)是区块链技术中两种常见的共识机制,它们在区块链网络中扮演着至关重要的角色,用于确保网络的安全性、去中心化和交易的验证。下面将分别详细解释这两种共识机制。 POW(工作量证明) 定义: POW,即工作量…

匿名管道 Linux

管道 首先自己要用用户层缓冲区&#xff0c;还得把用户层缓冲区拷贝到管道里&#xff0c;&#xff08;从键盘里输入数据到用户层缓冲区里面&#xff09;&#xff0c;然后用户层缓冲区通过系统调用&#xff08;write&#xff09;写到管道里&#xff0c;然后再通过read系统调用&…

[leetcode] 70. 爬楼梯

文章目录 题目描述解题方法动态规划java代码复杂度分析 题目描述 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; 示例 1&#xff1a; 输入&#xff1a;n 2 输出&#xff1a;2 解释&#xff1…

每一个云手机的ip是独立的吗

每一个云手机的IP地址通常是独立的。以下是关于云手机IP地址的一些详细信息&#xff1a; 1. 云手机的概念 云手机是将手机操作系统&#xff08;如Android&#xff09;虚拟化后托管在云服务器上的一种服务。用户可以通过互联网访问和控制这些云手机&#xff0c;进行应用使用、…

城市轨道交通网络客流大数据可视化分析系统----以某市交通网络客流数据为例

1 引言 1.1研究背景、目的与意义 1.1.1研究背景 城市轨道交通系统是现代城市的重要交通方式之一&#xff0c;随着城市化进程的加速和人口增长&#xff0c;轨道交通系统的客流量不断增加。因此&#xff0c;轨道交通部门和相关企业需要对客流数据进行实时监测和分析&#xff0…

BERT训练之数据集处理(代码实现)

目录 1读取文件数据 2.生成下一句预测任务的数据 3.预测下一个句子 4.生成遮蔽语言模型任务的数据 5.从词元中得到遮掩的数据 6.将文本转化为预训练数据集 7.封装函数类 8.调用 import os import random import torch import dltools 1读取文件数据 def _read_wiki(data_d…