【C】回调函数和qsort详解

news2024/11/23 7:41:54

回调函数概念

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

库函数qsort(在头文件stdlib.h中)

这个函数是一个排序函数,我们学过冒泡排序,但是那个排序能够排序整型,我们今天说的qsort可以排序任何类型,它默认排的是升序。我们来看一下他的参数列表:

void qsort( void *base, size_t num, size_t width, int (__cdecl *compare )(const void *elem1, const void *elem2 ) );

这里的void* 为无类型,因为可以排序任意类型的数组,所以不知道你的是哪种数组的指针用void* 来接收,size_t为无符号整型,num表示的是数组的大小,width为数组中每个元素多大,最后一个参数就是函数指针了,指向的是 int xxxx(const void *elem1, const void *elem2 ) 这样一个函数。再看下图:
在这里插入图片描述
如果elem1指向的内容大于elem2指向的内容就返回大于0的数字,如果等于就返回0,如果小于就返回小于0的数字。
那么接下来我们就上手来用下这个函数:

// qsort需要的函数
int sort_int(const void* p1, const void* p2)
{
	return *((int*)p1) - *((int*)p2);
}
// 打印函数
void print(int* arr, int size)
{
	for (int i = 0; i < size; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
}

int main()
{
	int arr[] = { 5,6,4,8,1,3,2,7,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);//计算数组大小
	qsort(arr, sz, sizeof(arr[0]), sort_int);
	print(arr, sz);
	return 0;
}

运行结果:

在这里插入图片描述
需要主要的是,void* 不能直接对它解引用操作,需要先强制类型转换,然后再操作。

qsort模拟实现

因为我们目前就学过冒泡排序,所以今天我们就用冒泡排序来模拟实现qsort.
我们将上面的代码拿下来,把qsort改为my_qsort.

int sort_int(const void* p1, const void* p2)
{
	return *((int*)p1) - *((int*)p2);
}
// 打印函数
void print(int* arr, int size)
{
	for (int i = 0; i < size; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
}

int main()
{
	int arr[] = { 5,6,4,8,1,3,2,7,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);//计算数组大小
	my_qsort(arr, sz, sizeof(arr[0]), sort_int);
	print(arr, sz);
	return 0;
}

那现在我们只需要实现my_qsort就可以了,我们这里传递的是整型数组,所以可以用整型指针来接受,但是我们qsort是可以排序任何类型的数据的,所以我们要用void* 来接受。所以函数的参数列表为:

void my_qsort(void* arr, size_t num, size_t width, int (cmp)(const void, const void*))

我们冒泡排序不管排什么数据,排的趟数肯定不会变的,而且每一趟比较的对数也是固定的,所以我们可以把冒泡排序的大体框架实现出来,这里的函数指针指向的函数就可以认为比较两个元素的大小的函数。我们的比较函数需要两个指针,也就是两个元素的地址,这时候我们传过来的元素大小就起到作用了,我们首元素的地址可以认为就是arr,第二个就是arr+1width,又因为只有arr是(char)类型是,我们才能实现每次跳的单位是1,所以我们在这之前要将arr强制转化为(char*)类型因为我们拍的元素是变化的,我们这里将参数设置为
(char*)arr+j* width,(char*)arr+(j+1)*width,这样我们就可以实现my_sort了。

void my_qsort(void* arr, size_t num, size_t width, int (*cmp)(const void*, const void*))
{
	for (unsigned int i = 0; i < num - 1; i++)
	{
		for (unsigned int j = 0; j < num - 1 - i; j++)
		{
			if (cmp((char*)(arr)+j*width,(char*)(arr)+(j+1)*width)>0)
			{
				Swap((char*)(arr) + j * width, (char*)(arr) + (j + 1) * width,width);
			}
		}
	}
}

这里就剩下一个Swap函数了,这个函数实现以后,我们的my_qsort就可以正常工作了。
因为我们还是要交换两个元素,所以我们要将两个元素的地址传过去,传过去的为(char*)类型的所以我们用char* 来接收就可以,又因为char*一次只能访问一个字节,如果我们要交换整型的话只需要将4个字节的内容都交换就可以了,所以我们还需要讲元素的大小过去。

void Swap(char* p1, char* p2, int width)
{
	char tmp = 0;
	for (int i = 0; i < width; i++)
	{
		tmp = *p1;
		*p1 = *p2;
		*p2 = tmp;
		p1++;
		p2++;
	}
}

到这里我们的qsort就实现完成了,我们来看一下运行结果:
在这里插入图片描述
我们可以看到我们的排序也没有问题。

今天的分享就到这里结束了,感谢大家的关注和支持!

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

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

相关文章

七大排序算法——快速排序,通俗易懂的思路讲解与图解(完整Java代码)

文章目录 一、排序的概念排序的概念排序的稳定性七大排序算法 二、快速排序核心思想Hoare法挖坑法前后指针法(选学) 三、性能分析四、算法优化优化基准的选取优化少量数据时的排序方案优化后的完整代码 五、七大排序算法 一、排序的概念 排序的概念 排序&#xff1a;所谓排序…

基于ChatGPT和私有知识库搭建Quivr项目

准备工作 安装docker和docker-compose申请supabase账号 拉取Quivr代码 git clone https://github.com/StanGirard/Quivr.git 复制.XXXXX_env文件 cp .backend_env.example backend/.env cp .frontend_env.example frontend/.env 更新backend/.env和frontend/.env文件 ba…

靶场的安装

sqli-lab 1.将安装包解压放到WWW目录下 2.修改 db-creds.inc文件里面的数据库的用户名密码为自己的用户名密码 路径&#xff1a;D:\phpStudy_64\phpstudy_pro\WWW\sqli-labs-master\sql-connections\db-creds.inc 3. 更改php版本位5.9版本&#xff0c;不然会报错 4.安装数…

【采用有限元法技术计算固有频率和欧拉屈曲荷载】使用有限元法的柱子的固有频率和屈曲荷载(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Android JNI 异常处理 (十一)

🔥 Android Studio 版本 🔥 🔥 创建包含JNI的类 JNIException.java 🔥 package com.cmake.ndk1.jni;public class JNIException {static {System.loadLibrary("exception-lib");}public native void nativeInvokeJavaException();public native void nativ…

B站这些“搬运工”还能有这么高的流量吗?

飞瓜数据&#xff08;B站版&#xff09;观察发现&#xff0c;B站经常有一些搬运视频能够获得超高流量。 比如拉取近15天的B站热门视频&#xff0c;位列前排的就有两个是搬运二创视频&#xff0c;播放量高达900万上下&#xff0c;可以说是爆款视频了。 这些视频有一个相同的点就…

Qt Https通信: TLS initialization failed 解决方法

Qt Https通信&#xff1a; TLS initialization failed 解决方法&#xff0c;Window端使用Qt 做开发请求Https资源时&#xff0c;会经常遇到 TLS initialization failed。 原因分析&#xff1a; 在Qt中并未包含 SSL所包含的库&#xff0c;因此需要开发者&#xff0c;自己将库拷贝…

最新华为鸿蒙4.0安装谷歌服务框架,安装Play商店,谷歌Google,GMS

最近华为推出了最新鸿蒙4.0开发者Beta版本&#xff0c;让用户测试体验。那么测试体验的机器主要是最近发布的几款机器为P60,P60 Pro, mate50,mate50 pro等几款产品可以先期进行体验测试鸿蒙4.0&#xff0c;那么很多的用户在疑问我升级到鸿蒙4.0。是不是还是可以使用Google谷歌服…

LINUX环境小实验

实验报告 实验名称 小环境搭设 实验目的 1.搭建DHCP服务器&#xff08;IP&#xff1a;192.168.100.253静态IP网卡vmnet1&#xff09; 2.搭建DNS&#xff08;通过DHCP服务器分到指定的IP&#xff1a;192.168.100.252&#xff09; 3.搭建网站服务&#xff08;通过DHCP服务器分…

波分复用(WDM)基本原理

文章目录 波分复用WDMDWDM解决问题&#xff0c;特点&#xff0d;超长距离无电中继传输&#xff0c;降低成本 波分系统的基本组成DWDM网元基本类型波分常见站点类型OM/OD技术&#xff0d;波分复用器主要参数 DWDM系统关键技术光转发技术 OM/OD技术&#xff0d;波分复用器件 波分…

Bun 0.6.14发布,1.0版预计发布于9月7日

Bun 是一个 JavaScript 运行时。 Bun 是一个从头开始构建的新 JavaScript 运行时&#xff0c;旨在服务现代 JavaScript 生态系统。它有三个主要设计目标&#xff1a; 速度。包子启动快&#xff0c;运行也快。它扩展了 JavaScriptCore&#xff0c;即为 Safari 构建的注重性能的 …

Office如何通过VSTO进行PPT插件开发?

文章目录 0.引言1.工具准备2.PPT外接程序创建和生成3.外接程序生成并使用 0.引言 VSTO&#xff08;Visual Studio Tools for Office &#xff09;是VBA的替代&#xff0c;是一套用于创建自定义Office应用程序的Visual Studio工具包。VSTO可以用Visual Basic 或者Visual C#扩展O…

EIK+Filebeat+Kafka

目录 Kafka 概述 为什么需要消息队列&#xff08;MQ&#xff09; 使用消息队列的好处 消息队列的两种模式 Kafka 定义 Kafka 简介 Kafka 的特性 Kafka 系统架构 Partation 数据路由规则&#xff1a; 分区的原因 部署 kafka 集群 1.下载安装包 2.安装 Kafka 修改配…

【979. 在二叉树中分配硬币】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 给定一个有 N 个结点的二叉树的根结点 root&#xff0c;树中的每个结点上都对应有 node.val 枚硬币&#xff0c;并且总共有 N 枚硬币。 在一次移动中&#xff0c;我们可以选择两个相邻的结点&#x…

【C++】list简单介绍

list基本功能介绍 前言正式开始构造函数push_backiteratorpush_frontinserterasespliceremoveuniquereversesortmerge 前言 本篇不会讲太多细节&#xff0c;就说一下STL库中一些函数的基本用法&#xff0c;如果想要了解细节上的东西的话&#xff0c;建议看我string的介绍&…

QT ui_xxx.h: no such file or directory”

使用QT新建子窗口后,编译无法通过 mainwindow.obj:-1: error: LNK2019: 无法解析的外部符号 "public: __cdecl labelwindow::labelwindow(class QWidget *)" (??0labelwindowQEAAPEAVQWidgetZ)&#xff0c;该符号在函数 "private: void __cdecl MainWindow::o…

android studio 添加并读取json配置文件

第一步&#xff1a;在android studio中添加json文件&#xff1b; 第二步&#xff1a;读取文件的函数 private String[] getJosnData(){String result[] null;List<String> list new ArrayList<>();try {//获取本地的Json文件AssetManager assetManager mConte…

界面控件DevExtreme v23.1新版亮点 - 全新的DateRangeBox组件

DevExtreme拥有高性能的HTML5 / JavaScript小部件集合&#xff0c;使您可以利用现代Web开发堆栈&#xff08;包括React&#xff0c;Angular&#xff0c;ASP.NET Core&#xff0c;jQuery&#xff0c;Knockout等&#xff09;构建交互式的Web应用程序。从Angular和Reac&#xff0c…

【Qt】 自定义列表控件

一、效果图 二、思路 先实现单个item控件&#xff0c;之后根据所需个数new出来插入布局中。item过多时支持滑动操作&#xff0c;可以把item放入scrollArea中&#xff0c;如需实现滑动效果可以使用eventFilter&#xff0c;计算坐标配合scrollArea->verticalScrollBar()->…