【C语言】回调函数,qsort排序函数的使用和自己实现,超详解

文章目录

  • 前言
  • 一、回调函数是什么
  • 二、回调函数的使用
    • 1.使用标准库中的qsort函数
    • 2.利用qsort函数对结构体数组进行排序
  • 三、实现qsort函数
  • 总结


在这里插入图片描述
先记录一下访问量突破2000啦,谢谢大家支持!!!
这里是上期指针进阶链接,方便大家查看:添加链接描述

前言

大家好呀,今天分享一下上期指针进阶中剩余的内容——回调函数,这个很重要滴,让我们一起来学会学懂他吧!!!


一、回调函数是什么

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

简单来说就是:在另一个函数中利用函数指针调用的函数叫做回调函数

二、回调函数的使用

1.使用标准库中的qsort函数

qsort函数不仅可以排序整型数组,还可以排序结构体等数据类型

代码如下:

#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);//qsort的第一个参数是排序数组的首元素地址//第二个参数是排序的长度//第三个参数是每个元素的大小//第四参数是使用者自己写的排序依据函数的地址(这里就是使用回调函数)for (i = 0; i< sizeof(arr) / sizeof(arr[0]); i++){printf( "%d ", arr[i]);}printf("\n");return 0;
}

整型数组排序的运行结果展示:
在这里插入图片描述

2.利用qsort函数对结构体数组进行排序

先看代码如下:

#include<stdio.h>
#inlcude<string.h>
struct stu {int age;char name[20];double score;
};
//依据年龄大小排序的比较函数
int compar_by_age(const void* e1, const void* e2)
{return ((struct stu*)e1)->age - ((struct stu*)e2)->age;
}
//依据名字排序的比较函数
int compar_by_name(const void* e1, const void* e2)
{return strcmp(((struct stu*)e1)->name, ((struct stu*)e2)->name);
}
int main()
{
//这是定义一个结构体类型的数组struct stu S[3] = { {21,"FRH",100},{19,"MSY",90},{18,"LZY",85} };int Ssz = sizeof(S) / sizeof(S[0]);qsort(S, Ssz, sizeof(S[0]), compar_by_age);qsort(S, Ssz, sizeof(S[0]), compar_by_name);return 0;
}

排序前后结果对比:
这是排序前结构体数组的顺序:
在这里插入图片描述
这是按照年龄排序后的顺序:
在这里插入图片描述
这是按照姓名排序后的顺序:
在这里插入图片描述

三、实现qsort函数

我们先来看一下qsort函数在标准库中的模样:
在这里插入图片描述
他没有返回值,四个参数分别是:
1、qsort的第一个参数是排序数组的首元素地址
2、第二个参数是排序的长度
3、第三个参数是每个元素的大小
4、第四参数是使用者自己写的排序依据函数的地址(这里就是使用回调函数)

作者是依据冒泡排序实现的qosrt函数,我们之间上代码:
#include<stdio.h>
#inlcude<string.h>
//依据名字排序的比较函数
int compar_by_name(const void* e1, const void* e2)
{return strcmp(((struct stu*)e1)->name, ((struct stu*)e2)->name);
}
//依据整型大小排序的比较函数
int int_cmp(const void * p1, const void * p2)
{//这里都会将接收到的地址转换为所需要比较的类型return (*( int *)p1 - *(int *) p2);
}//这里排序中交换两个元素的交换函数
void Swap(char* x, char* y,int size)
{
//利用char* 接收需要交换的元素,可以保证对其每个字节进行交换从而实现整体全部字节的交换
//size就是该元素所占字节的大小,决定每次交换循环几次int i = 0;for (i = 0; i < size; i++){char temp = *x;*x = *y;*y = temp;x++;y++;}
}void Bubble_Sort(void* base, size_t num, size_t size,int (*compar)(const void*, const void*))
{int i = 0;for (i = 0; i < num - 1; i++){int j = 0;for (j = 0; j < num - 1 - i; j++){//为什么要将首元素地址转换为char* 类型呢?//因为:这样可以保证任何类型数组在排序比较时能够访问到其中的每一个元素//这个设计是真的巧妙if (compar(((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] = { 9,8,7,6,5,4,3,2,1,0 };struct stu S[3] = { {21,"FRH",100},{19,"MSY",90},{18,"LZY",85} };int Ssz = sizeof(S) / sizeof(S[0]);int sz = sizeof(arr) / sizeof(arr[0]);Bubble_Sort(arr,sz,sizeof(arr[0]),compar_by_int);Print(arr, sz);Bubble_Sort(S, Ssz, sizeof(S[0]), compar_by_age);Bubble_Sort(S, Ssz, sizeof(S[0]), compar_by_name);return 0;
}

可以得到,排序结果和上面调用标注库中qsort函数的结果是相同的
在这里插入图片描述

总结

关于回调函数的分享就到这里啦,希望qsort函数可以帮助到大家,博主感觉他真的是很有用,以后会尽量使用到他的,希望本篇文章可以帮助到大家,谢谢大家阅读!!!

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

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

相关文章

金融术语总结

洗钱 将犯罪或其他非法违法行为所获得的违法收入&#xff0c;通过各种手段掩饰、隐瞒、转化&#xff0c;使其在形式上合法化的行为。 存量客户 某个时间段里原先已有的客户,与新增客户相对应。 月活跃用户数量&#xff0c;MAU&#xff08;Monthly Active User&#xff0c;M…

【go语言基础】go中的方法

先思考一个问题&#xff0c;什么是方法&#xff0c;什么是函数&#xff1f; 方法是从属于某个结构体或者非结构体的。在func这个关键字和方法名中间加了一个特殊的接收器类型&#xff0c;这个接收器可以是结构体类型的或者是非结构体类型的。从属的结构体获取该方法。 函数则…

【100天精通python】Day37:GUI界面编程_PyQT从入门到实战(上)

目录 专栏导读 1 PyQt6 简介&#xff1a; 1.1 安装 PyQt6 和相关工具&#xff1a; 1.2 PyQt6 基础知识&#xff1a; 1.2.1 Qt 的基本概念和组件&#xff1a; 1.2.2 创建和使用 Qt 窗口、标签、按钮等基本组件 1.2.3 布局管理器&#xff1a;垂直布局、水平布局、网格布局…

typedef函数代码段解释以及部分Windows下的系统函数

文章目录 1、typedef int (WINAPI* LPSDOLInitialize)(const SDOLAppInfo* pAppInfo)2、typedef int (WINAPI* LPSDOLGetModule)(REFIID riid, void** intf)3、typedef int (WINAPI* LPSDOLTerminal)();4、GetProcAddress运行时获取一个动态链接库&#xff08;DLL&#xff09;中…

mysql与redis区别

mysql和redis的数据库类型 mysql是关系型数据库&#xff0c;主要用于存放持久化数据&#xff0c;将数据存储在硬盘中&#xff0c;读取速度较慢。 redis是NOSQL&#xff0c;即非关系型数据库&#xff0c;也是缓存数据库&#xff0c;即将数据存储在缓存中&#xff0c;缓存的读取速…

网络

mcq Java 传输层&#xff1a;拆分和组装&#xff0c;完成端到端的消息传递&#xff0c;流量控制&#xff0c;差错控制等 网络层&#xff1a; 寻址、路由&#xff0c;复用&#xff0c;拥塞控制&#xff0c;完成源到宿的传递。 显然A选项是错误的&#xff0c;有流量控制的是传输层…

JavaScript TypeScript

文章目录 JavaScript语法事件处理与HTML和CSS集成前端框架和库 TypeScript静态类型检查语法更好的可维护性 包管理工具npmpnpmyarnBower JavaScript JavaScript&#xff08;简称JS&#xff09;是一种广泛应用于网页开发的脚本语言。它被用来为网页增加交互性和动态功能。以下是…

netty学习分享(一)

TCP与UDP TCP 是面向连接的、可靠的流协议&#xff0c;通过三次握手建立连接&#xff0c;通讯完成时要拆除连接。 UDP是面向无连接的通讯协议&#xff0c;UDP通讯时不需要接收方确认&#xff0c;属于不可靠的传输&#xff0c;可能会出现丢包现象 端口号&#xff1a; 端口号用…

【微信小程序】记一次自定义微信小程序组件的思路

最近来个需求&#xff0c;要求给小程序的 modal 增加个关闭按钮&#xff0c;上网一查发现原来 2018 年就有人给出解决方案了&#xff0c;于是总结下微信小程序自定义组件的思路&#xff1a;一句话&#xff0c;用 wxml css实现和原生组件类似的样式和效果&#xff0c;之后用 JS…

【uniapp】uniapp设置安全区域:

文章目录 一、效果图:二、实现代码: 一、效果图: 二、实现代码: {"path": "pages/index/index","style": {"navigationStyle": "custom","navigationBarTextStyle": "white","navigationBarTitle…

消息队列学习笔记

消息队列基础 适合消息队列解决的问题 异步处理&#xff1a;处理完关键步骤后直接返回结果&#xff0c;后续放入队列慢慢处理流量控制&#xff1a; 使用消息队列隔离网关和后端服务&#xff0c;以达到流量控制和保护后端服务的目的。能根据下游的处理能力自动调节流量&#x…

leetcode做题笔记79单词搜索

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 单词必须按照字母顺序&#xff0c;通过相邻的单元格内的字母构成&#xff0c;其中“相邻”单元格是那些水平相邻或垂直相…

Matlab工具NIFTI包的基本功能函数

Matlab工具NIFTI包的基本功能函数 Nifti 格式最初是为神经影像学发明的。神经影像信息学技术计划&#xff08;NIFTI&#xff09;将 NIfTI 格式预设为 ANALYZE7.5 格式的替代品。它最初的应用领域是神经影像&#xff0c;但是也被用在其他领域。这种格式的主要特点就是它包含两个…

Docker基础入门:常规软件安装与镜像加载原理

Docker基础入门&#xff1a;常规软件安装与镜像加载原理 一、Docker常规软件安装1.1、部署nginx1.2、部署tomcat1.3、部署elasticsearch1.4、如何部署kibana-->连接elasticsearch1.5、部署可视化工具 二、 镜像加载原理2.1、镜像是什么2.2、Docker镜像加速原理2.3、分层理解…

为什么我的集群一个 Spark Executor / Yarn Container 只分配一个vCore?

在很多集群里,在关闭了Spark的DynamicAllocation的前提下(避免自动申请空闲资源,干扰测试结果),都会观察到:提交Spark作业时,申请 1 个 driver + n 个 executor 会在Yarn上对应创建 n+1 个 container,但是每个container只有一个vCore,通过--driver-cores和--executor-…

Grafana Prometheus 通过JMX监控kafka 【2023最新方式】

第三方kafka exporter方案 目前网上关于使用Prometheus 监控kafka的大部分资料都是使用一个第三方的 kafka exporter&#xff0c;他的原理大概就是启动一个kafka客户端&#xff0c;获取kafka服务器的信息&#xff0c;然后提供一些metric接口供Prometheus使用&#xff0c;随意它…

docker 安装mysql8.0

1、拉取镜像 docker pull mysql2、运行镜像 docker run -d --restartalways --name mysql --privilegedtrue -p 3306:3306 -v /home/sunyuhua/docker/mysql/data:/var/lib/mysql -v /home/sunyuhua/docker/mysql/conf:/etc/mysql/conf.d -v /home/sunyuhua/docker/mysql/logs…

07_Hudi案例实战、Flink CDC 实时数据采集、Presto、FineBI 报表可视化等

7.第七章 Hudi案例实战 7.1 案例架构 7.2 业务数据 7.2.1 客户信息表 7.2.2 客户意向表 7.2.3 客户线索表 7.2.4 线索申诉表 7.2.5 客户访问咨询记录表 7.3 Flink CDC 实时数据采集 7.3.1 开启MySQL binlog 7.3.2 环境准备 7.3.3 实时采集数据 7.3.3.1 客户信息表 7.3.3.2 客户…

ubuntu安装jdk、emqx、nginx

一、安装jdk 要在Ubuntu上安装JDK 1.8&#xff0c;您可以按照以下步骤进行操作&#xff1a; 打开终端&#xff08;CtrlAltT&#xff09;。确保您的系统已更新&#xff1a; sudo apt update sudo apt upgrade安装OpenJDK 8&#xff1a; sudo apt install openjdk-8-jdk安装完成…

.net core发布到IIS上出现 HTTP 错误 500.19

1.检查.net core 环境运行环境是否安装完成&#xff0c;类似如下环境 2.IIS是否安装全 本次原因就是IIS未安装全导致的 按照网上说的手动重启iis&#xff08;iisreset&#xff09;也不行