【c语言】qsort函数及泛型冒泡排序的模拟实现
🌟🌟作者主页:ephemerals__
🌟🌟所属专栏:C语言
目录
一、qsort函数
1.回调函数
2.qsort函数
3.void* 指针
二、泛型冒泡排序的模拟实现
1.比较函数的编写
2.交换函数的编写
3.冒泡排序的编写
4.全部代码和使用示例
总结
一、qsort函数
1.回调函数
在了解qsort函数之前,我们先来学习一个概念:回调函数。那么回调函数是什么呢?
简单地说,回调函数就是通过函数指针调用的函数。
如果你将函数A的地址传给另外一个函数B,当B通过这个地址调用函数A时,函数A就称作回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或者条件进行响应。
2.qsort函数
在了解了回调函数的概念后,我们来学习一下qsort函数。qsort函数是c语言标准库下的一个函数,它的作用是对任意类型的数据进行排序。我们在cplusplus上搜索一下它:

可以看到,这个函数在使用的时候需要引头文件<stdlib.h>。它有四个参数,其中第四个参数就是一个函数指针。我们再观察一下四个参数的内容:

第一个参数是一个指向数组首元素的指针base,它会被转换为void*类型的指针。
第二个参数是这个数组中的元素个数num,类型是size_t。
第三个参数是数组中每一个元素的内存大小size。
第四个参数是一个函数指针compar,这个函数指针指向的函数用于比较两个元素,也就是说,在qsort函数执行排序功能时,需要调用我们自己写的元素比较函数。对于比较函数,如果第一个参数小于第二个参数,就返回负数,反之就返回正数,相等则返回0。
可以看出,qsort函数是通过compar函数的地址调用它的,所以这里的compar函数就是一个回调函数。
好,我们现在来试着使用一下qsort函数:
#include <stdio.h>
#include <stdlib.h>int cmp_int(const void* p1, const void* p2)
{return *(int*)p1 - *(int*)p2;//对int类型数据进行比较,将void*型指针强制转换为int*类型
}int main()
{int arr[10] = { 2,10,5,4,9,3,6,8,1,7 };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(int), cmp_int);for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}return 0;
}
运行结果:

可以看到,数组的元素确实被排序过来了。
3.void* 指针
刚才的代码当中,我们使用了void*类型的指针作为形参。我们来着重介绍一下void*类型的指针。
void*类型的指针也叫做无具体类型的指针,它的作用是可以接收任何类型的指针,常常存在于形参之中。当使用void*类型的指针时,它是无法直接进行解引用操作的,需要将其强制类型转换为其他类型的指针,才能确定访问的字节数,从而继续使用。
二、泛型冒泡排序的模拟实现
接下来,我们基于能够排序任意类型的数据qsort函数,模拟实现一个冒泡排序,能够排序任意类型的数据。
1.比较函数的编写
首先我们来编写比较函数。以int类型为例,将void*指针转换为int*类型即可。
int cmp_int(const void* p1, const void* p2)
{return *(int*)p1 - *(int*)p2;
}
这里将传入元素的地址,之后以int类型的形式访问四个字节,然后进行大小比较,前者大于后者
则返回正数,否则返回负数,相等返回0。
2.交换函数的编写
接下来我们写一个函数来实现元素的交换(注意:这里由于不知要交换什么类型的元素,所以要转换为char*类型的指针,然后一个字节一个字节地交换):
void swap(void* p1, void* p2, size_t size)
{int i = 0;char tmp = 0;for (i = 0; i < size; i++)//一个字节一个字节地交换,交换size次{tmp = *((char*)p1 + i);*((char*)p1 + i) = *((char*)p2 + i);*((char*)p2 + i) = tmp;}
}
注意:由于强制类型转换是临时的,所以每一次使用的时候都要进行强制类型转换。
为了便于大家理解这里的交换过程,我们画图演示一下:

3.冒泡排序的编写
冒泡排序的编写大体和原本的冒泡排序相同,但是有些细节需要处理:
void bubble_sort(void* base, size_t num, size_t sinumze, int(*cmp)(const void*, const void*))
{int i = 0;int j = 0;for (i = 0; i < num - 1; i++){for (j = 0; j < num - 1 - i; j++){//这里需要将数组中下标为j和j+1的元素进行比较,所以将base强制转换为char*类型,然后加上相应内存大小的j倍或j+1倍就可以得到第j和j+1个元素的地址if (cmp((char*)base + size * j, (char*)base + size * (j + 1)) > 0){//相同道理,交换第j和j+1个元素swap((char*)base + size * j, (char*)base + size * (j + 1), size);}}}
}
4.全部代码和使用示例
程序全部代码:
int cmp_int(const void* p1, const void* p2)
{return *(int*)p1 - *(int*)p2;
}void swap(void* p1, void* p2, size_t size)
{int i = 0;char tmp = 0;for (i = 0; i < size; i++)//一个字节一个字节地交换,交换size次{tmp = *((char*)p1 + i);*((char*)p1 + i) = *((char*)p2 + i);*((char*)p2 + i) = tmp;}
}void bubble_sort(void* base, size_t num, size_t size, int(*cmp)(const void*, const void*))
{int i = 0;int j = 0;for (i = 0; i < num - 1; i++){for (j = 0; j < num - 1 - i; j++){//这里需要将数组中下标为j和j+1的元素进行比较,所以将base强制转换为char*类型,然后加上相应内存大小的j倍或j+1倍就可以得到第j和j+1个元素的地址if (cmp((char*)base + size * j, (char*)base + size * (j + 1)) > 0){//相同道理,交换第j和j+1个元素swap((char*)base + size * j, (char*)base + size * (j + 1), size);}}}
}
接下来我们试着使用一下,看看是否能够排序成功:

可以看到,排序成功了。大家也可以尝试编写其他类型的比较函数来进行排序。
像这种可以针对任意类型的编程方法,我们称之为泛型编程。泛型编程提高了代码的重复利用率,增加了程序安全性和执行效率。
总结
今天我们学习了qsort函数及泛型冒泡排序的模拟实现,由此可以看出泛型编程的好处。之后博主会和大家介绍一些c语言中的常见字符串函数,并且模拟实现。如果你觉得博主讲的还不错,就请留下一个小小的赞在走哦,感谢大家的支持❤❤❤
相关文章:
【c语言】qsort函数及泛型冒泡排序的模拟实现
🌟🌟作者主页:ephemerals__ 🌟🌟所属专栏:C语言 目录 一、qsort函数 1.回调函数 2.qsort函数 3.void* 指针 二、泛型冒泡排序的模拟实现 1.比较函数的编写 2.交换函数的编写 3.冒泡排序的编写 4…...
MySQL之多表查询—表子查询
一、引言 上一篇博客学习了行子查询。(看弹幕:同一张表用or,不同张表用union) 下面接着学习子查询当中的最后一种——表子查询。 表子查询 1、概念 子查询返回的结果是多行多列,这种子查询称为表子查询。 2、常用的操作符 IN 3、…...
Java 18风暴来袭:解锁编程新纪元
一、引言 Java 18的发布标志着Java语言在性能、安全性和开发效率方面的又一次飞跃。本次更新不仅带来了新的语言特性,还包括了一些实验性功能和工具的改进。这些新特性旨在帮助开发者编写更高效、更安全的代码,并提升开发体验。 二、新特性概述 1. 默…...
文件操作(Python和C++版)
一、C版 程序运行时产生的数据都属于临时数据,程序—旦运行结束都会被释放通过文件可以将数据持久化 C中对文件操作需要包含头文件< fstream > 文件类型分为两种: 1. 文本文件 - 文件以文本的ASCII码形式存储在计算机中 2. 二进制文件- 文件以文本的二进…...
Git【版本控制命令】
02 【本地库操作】 1.git的结构 2.Git 远程库——代码托管中心 2.1 git工作流程 代码托管中心用于维护 Git 的远程库。包括在局域网环境下搭建的 GitLab 服务器,以及在外网环境下的 GitHub 和 Gitee (码云)。 一般工作流程如下: 1.从远程…...
打字侠是一款PWA网站,如何下载到电脑桌面?
嘿,亲爱的键盘侠们! 你是否还在为寻找一款好用的打字练习工具而烦恼?别担心,今天我要给大家介绍一位超级英雄——打字侠!它不仅是一个超级酷的打字练习网站,还是一款PWA(渐进式网页应用&#x…...
Scikit-learn使用步骤?使用场景?
Scikit-learn(简称sklearn)是Python中一个非常流行的机器学习库,它提供了广泛的机器学习算法和工具,用于数据分析、特征工程、模型训练、模型评估等任务。以下是一个关于sklearn的基础教程,内容将按照几个主要部分进行…...
MySQL 5.7详细下载安装配置教程(MySQL 5.7安装包)_mysql5.7的安装教程
记录MySQL 5.7 的下载安装教程,并提供了Mysql 安装包 ,以下是详细下载安装过程。 一、下载Mysql安装包 网盘下载: 下载MySQL 5.7安装包,网盘下载地址:点击此处直接下载 官网下载: 进入官网,…...
电阻十大品牌供应商
选型时选择热门的电阻品牌,主要是产品丰富,需求基本都能满足。 所所有的电路中,基本没有不用电阻的,电阻的选型需要参考阻值、精度、封装、温度范围,贴片/插件等参数,优秀的供应商如下: 十大电…...
深度学习复盘与论文复现C
文章目录 4、Distributed training4.1 GPU architecture 5、Recurrent neural network5.1 The basic structure of RNN5.2 Neural networks without hidden states5.3 Recurrent neural networks with hidden states5.4 summary 6、Language Model Dataset (lyrics from Jay Ch…...
海洋日特别活动—深海来客——可燃冰
深海中有一种神奇的物质,似冰又不是冰。 别看它其貌不扬,但本领不小,遇火即燃,能量巨大,可谓是能源家族的新宠。它就是被国务院正式批准列为我国第173个矿种的“可燃冰”! 可燃冰到底是个啥?它…...
Web前端放图片位置:深入探索与最佳实践
Web前端放图片位置:深入探索与最佳实践 在Web前端开发中,图片作为重要的视觉元素,其放置位置往往影响着网页的整体布局和用户体验。然而,如何合理地放置图片,以最大化其视觉效果并提升用户体验,却是一个颇…...
leetcode-02-[977]有序数组的平方[209]长度最小的子数组[59]螺旋矩阵II
一、[977]有序数组的平方 重点: 新引入一个数组,不要原数组操作 class Solution {public int[] sortedSquares(int[] nums) {int left0,right nums.length-1;int[] resultnew int[nums.length];int index nums.length-1;while(left<right){if(nums…...
Spring Cloud Gateway CORS 跨域方案
通过配置文件,以下配置就是其中一种方案。 gateway: #跨域配置globalcors: cors-configurations: [/**]: allowedMethods: "*"allowedHeaders: "*"allowedOriginPatterns: "*"allowCredentials: truedefault-filters: - DedupeRespo…...
高考后志愿填报信息采集系统制作指南
在高考的硝烟散去之后,每位学生都面临着一个重要的任务——志愿填报。老师们如何高效、准确地收集和整理这些信息,成为了一个棘手的问题。难道我们只能依赖传统的手工登记方式,忍受其繁琐和易错吗? 易查分是一个简单易用的在线工具…...
Python使用Flask构建简单的web应用
构建一个简单的 Flask Web 应用程序是学习 Python Web 开发的良好起点。Flask 是一个轻量级的 WSGI Web 应用框架,它的主要目标是让开发者更容易构建 Web 应用,同时保持简单性和灵活性。下面我们将详细介绍如何使用 Flask 构建一个简单的 Web 应用&#…...
看似不同的事情,却是相同的坑
目录 一、背景二、过程1.遭遇战-微盘股的下杀2.不失为一件好事3.一切向后看吧,最近的学习感受4.该有的心境 三、总结 一、背景 也在一点点改变,期间势必要经历流血的过程;所谓无疯狂不成长,积极的心态去应对,去总结总…...
在 Linux 系统上安装 Android NDK
在 Linux 系统上安装 Android NDK 1. Android NDK2. NDK Downloads2.1. Latest LTS Version (r26d)2.2. Old Unsupported Versions 3. 安装 NDK4. Get started with the NDK (NDK 使用入门)References 1. Android NDK https://developer.android.com/ndk The Android NDK is …...
SpringBoot的学习要点
目录 SpringBoot 创建项目 配置文件 注解 命名规范 SpringBoot整合第三方技术 …… 中文文档:Spring Boot 中文文档 SpringBoot Spring Boot 是基于 Spring 框架的一种快速构建微服务应用的方式它主要提供了自动配置、简化配置、运行时应用监控等功能它…...
vue3引入cesium和olcs
首先引入包 pnpm i olcs; pnpm i -D vite-plugin-cesium pnpm i -S cesium在vite.config.js中配置,参考这位大佬的笔记 添加链接描述 import { defineConfig } from vite import vue from vitejs/plugin-vue import cesium from vite-plugin-cesium; // https://…...
终极指南:如何用Zotero PDF Translate插件快速突破学术语言壁垒
终极指南:如何用Zotero PDF Translate插件快速突破学术语言壁垒 【免费下载链接】zotero-pdf-translate 支持将PDF、EPub、网页内容、元数据、注释和笔记翻译为目标语言,并且兼容20多种翻译服务。 项目地址: https://gitcode.com/gh_mirrors/zo/zotero…...
RMBG-2.0抠图工具性能测试:RTX 3060上平均1.8秒处理一张图
RMBG-2.0抠图工具性能测试:RTX 3060上平均1.8秒处理一张图 1. 为什么选择本地抠图工具? 在日常工作和内容创作中,我们经常需要处理图片背景去除的需求。无论是电商产品图、社交媒体配图还是设计素材,一个高效的抠图工具可以大幅…...
MusePublic Art Studio惊艳效果:动态种子演化生成同主题12张连贯艺术组图
MusePublic Art Studio惊艳效果:动态种子演化生成同主题12张连贯艺术组图 1. 引言:当AI成为艺术家的画笔 想象一下,你是一位艺术家,脑海中有一个绝妙的创意主题。你想围绕这个主题创作一个系列作品,比如“赛博朋克森…...
ChatGLM3-6B-128K部署指南:Ollama环境配置避坑大全
ChatGLM3-6B-128K部署指南:Ollama环境配置避坑大全 本文面向需要处理长文本任务的开发者和研究者,手把手教你如何快速部署ChatGLM3-6B-128K模型,避开环境配置中的常见坑点。 1. 环境准备与快速部署 在开始部署之前,我们先简单了解…...
Kaggle Notebook中文乱码终结者:3分钟搞定Matplotlib字体配置(附Noto Sans CJK全流程)
Kaggle Notebook中文乱码终结者:3分钟搞定Matplotlib字体配置(附Noto Sans CJK全流程) 在数据可视化过程中,中文显示问题一直是困扰许多Kaggle用户的痛点。当你在Notebook中满怀期待地运行代码,却发现图表中的中文变成…...
为什么你的Monte Carlo期权定价结果总偏差>8%?:揭秘随机数种子、路径步长与方差缩减的3重陷阱
第一章:Monte Carlo期权定价偏差的典型现象与问题界定Monte Carlo方法在欧式、亚式及路径依赖型期权定价中广泛应用,但其数值结果常表现出系统性偏差——并非源于算法逻辑错误,而是由随机采样、方差结构与边界处理等多重因素耦合所致。实践中…...
React-PDF自定义字体粗细终极指南:实现精确文本字重控制的完整教程
React-PDF自定义字体粗细终极指南:实现精确文本字重控制的完整教程 【免费下载链接】react-pdf 📄 Create PDF files using React 项目地址: https://gitcode.com/gh_mirrors/re/react-pdf React-PDF是一个功能强大的库,允许开发者使用…...
YOLOv8自定义检测头踩坑记:手把手教你修复‘NotImplementedError: new_detect task‘错误
YOLOv8自定义检测头实战:从报错到修复的深度解析 当你在YOLOv8框架中尝试添加一个名为new_detect的自定义检测头时,突然遇到NotImplementedError: new_detect task错误,这可能会让你感到困惑。本文将带你深入理解YOLOv8的任务调度机制&#x…...
别再手动校正了!用Landsat 9 L2SP地表反射率数据,在QGIS里5分钟搞定NDVI和水体提取
遥感分析效率革命:用Landsat 9 L2SP数据在QGIS中实现5分钟精准制图 当遥感数据处理流程从传统数小时缩短至五分钟,这意味着什么?去年在亚马逊雨林监测项目中,我们团队曾因大气校正步骤延误错过了最佳干预时机。如今Landsat 9 L2SP…...
不用命令行!Win11任务栏图标消失的图形化解决方案(Explorer重启神器推荐)
Win11任务栏图标消失?5种可视化修复方案与深度解析 每次切换虚拟桌面后,Win11任务栏图标集体"失踪"的毛病,堪称微软系统最顽固的"幽灵故障"之一。作为从Windows 95时代就存在的资源管理器痼疾,这个问题在Win1…...
