【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.hqwc.cn/news/66255.html

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

相关文章

Kafka API与SpringBoot调用

文章目录 首先需要命令行创建一个名为cities的主题&#xff0c;并且创建该主题的订阅者。 1、使用Kafka原生API1.1、创建spring工程1.2、创建发布者1.3、对生产者的优化1.4、批量发送消息1.5、创建消费者组1.6 消费者同步手动提交1.7、消费者异步手动提交1.8、消费者同异步手动…

Mybatis 源码 ∞ :杂七杂八

文章目录 一、前言二、TypeHandler三、KeyGenerator四、Plugin1 Interceptor2 org.apache.ibatis.plugin.Plugin3. 调用场景 五、Mybatis 嵌套映射 BUG1. 示例2. 原因3. 解决方案 六、discriminator 标签七、其他1. RowBounds2. ResultHandler3. MapKey 一、前言 Mybatis 官网…

顺序表的插入,删除,修改和查找(详细解析)

目录 一.顺序表的初始化----静态分配 二.顺序表的初始化----动态分配 三.顺序表的插入 1.插入操作 2.插入操作的时间复杂度 三.顺序表的删除操作 1.顺序表的删除 2.删除操作的时间复杂度 四.顺序表的查找 1.按位查找操作&#xff1a;查找第i位置的元素 2.按位查找操作…

用友时空KSOA SQL注入漏洞复现(HW0day)

0x01 产品简介 用友时空KSOA是建立在SOA理念指导下研发的新一代产品&#xff0c;是根据流通企业最前沿的I需求推出的统一的IT基础架构&#xff0c;它可以让流通企业各个时期建立的IT系统之间彼此轻松对话&#xff0c;帮助流通企业保护原有的IT投资&#xff0c;简化IT管理&#…

面试笔记:Android 架构岗,一次4小时4面的体验

作者&#xff1a;橘子树 此次面试一共4面4小时&#xff0c;中间只有几分钟间隔。对持续的面试状态考验还是蛮大的。 关于面试的心态&#xff0c;保持悲观的乐观主义心态比较好。面前做面试准备时保持悲观&#xff0c;尽可能的做足准备。面后积极做复盘&#xff0c;乐观的接受最…

测试开发探索:“WeTalk“网页聊天室的测试流程与自动化

目录 引言&#xff1a; 测试开发目标&#xff1a; "WeTalk"项目背景 关于登录测试用例的设计 测试开发策略与流程 集成测试&#xff1a;Selenium JUnit 接口测试&#xff1a;Postman 测试用例的设计与实现 自动化测试演示&#xff1a; 用例一&#xff1a;登…

K8s环境下监控告警平台搭建及配置

Promethues是可以单机搭建的&#xff0c;参考prometheus入门[1] 本文是就PromethuesGrafana在K8s环境下的搭建及配置 Prometheus度量指标监控平台简介 启动minikube minikube start 安装helm 使用Helm Chart 安装 Prometheus Operator: helm install prometheus-operator stabl…

vscode-启动cljs

打开vscode &#xff0c;打开cljs项目文件 先npm installvscode安装插件Calva: Clojure & ClojureScript启动REPL 选择Start yout project with a REPL and connect(a.k.a. jack) 后选择shadow-cljs&#xff0c;然后选择shadow&#xff0c;如果需要选择build的话&#xf…

Java课题笔记~ Spring 集成 MyBatis

Spring 集成 MyBatis 将 MyBatis 与 Spring 进行整合&#xff0c;主要解决的问题就是将 SqlSessionFactory 对象交由 Spring 来管理。所以该整合&#xff0c;只需要将 SqlSessionFactory 的对象生成器SqlSessionFactoryBean 注册在 Spring 容器中&#xff0c;再将其注入给 Dao…

MyBatis-Plus学习笔记(尚硅谷)

一、MyBatis-Plus 1.简介 MyBatis-Plus (opens new window)&#xff08;简称 MP&#xff09;是一个 MyBatis (opens new window)的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。 我们的愿景是成为 MyBatis 最好的搭档&…

Centos7.9上(离线)安装Gitlab

1、下载Gitlab的rpm安装包Index of /gitlab-ce/yum/el7/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 2、安装rpm -i gitlab-ce-10.0.0-ce.0.el7.x86_64.rpm&#xff0c;如果依赖缺失&#xff0c;yum安装即可 3、vi /etc/gitlab/gitlab.rb 配置external_url&…

【Flutter】【基础】CustomPaint 绘画功能(一)

功能&#xff1a;CustomPaint 相当于在一个画布上面画画&#xff0c;可以自己绘制不同的颜色形状等 在各种widget 或者是插件不能满足到需求的时候&#xff0c;可以自己定义一些形状 使用实例和代码&#xff1a; CustomPaint&#xff1a; 能使你绘制的东西显示在你的ui 上面&a…