深入理解指针(4)(C语言版)
文章目录
- 前言
- 一、回调函数是什么
- (一)定义
- (二)工作原理
- (三)应用场景
- 二、qsort举例
- (一)qsort函数简介
- (二)比较函数的定义
- (三)使用示例
- 三、qsort函数的模拟实现(冒泡排序)
- (一)基本思路
- (二)模拟qsort函数的实现
- (三)测试模拟实现
- 总结
前言
在C语言中,指针一直是一个让初学者头疼却又无法绕开的话题。它既强大又灵活,但同时也容易出错。对指针的深入理解,是每个C语言程序员成长过程中的必经之路。在之前的几篇博客中,我们已经探讨了指针的基础概念、数组与指针的关系、指针与字符串等内容。今天,我们将继续深入,探讨指针在回调函数中的应用,并以qsort函数为例,进行详细讲解和模拟实现。
一、回调函数是什么
(一)定义
回调函数,简单来说,就是一个通过函数指针调用的函数。在程序运行过程中,当我们需要将某个函数的地址传递给另一个函数,然后在适当的时候由后者调用前者,这个被调用的函数就被称为回调函数。
(二)工作原理
回调函数的工作原理基于函数指针。在C语言中,函数指针是一种特殊的指针类型,它指向一个函数的入口地址。当我们把一个函数的指针作为参数传递给另一个函数时,接收方可以通过这个指针来调用对应的函数。这种机制使得程序在运行时具有更高的灵活性和可扩展性,因为它允许我们在不修改原有函数代码的情况下,通过传入不同的回调函数来改变其行为。
(三)应用场景
回调函数在很多场景中都有广泛的应用。例如,在图形用户界面编程中,我们经常会为按钮、菜单等控件设置回调函数,当用户触发相应事件(如点击按钮)时,系统会调用我们预先设定的回调函数来处理该事件。此外,在多线程编程中,回调函数也常用于线程的创建和同步操作,通过指定线程函数的指针来实现特定任务的执行。还有像数据排序、算法库等,也会利用回调函数来自定义排序规则或提供扩展接口,以满足不同用户的需求。
二、qsort举例
(一)qsort函数简介
qsort函数是C标准库中的一个快速排序函数,它位于stdlib.h头文件中。其函数原型为:
void qsort(void *base, size_t num, size_t width, int (*comp)(const void *, const void*));
其中,base是指向要排序的数组首元素的指针;num是数组中元素的个数;width是每个元素的大小(以字节为单位);comp是一个指向比较函数的指针,用于定义排序规则。
(二)比较函数的定义
比较函数是qsort函数的核心部分,它决定了排序的顺序。该函数的类型为int (*)(const void , const void),即它接收两个指向const void类型的指针作为参数,返回一个int类型的整数。在比较函数中,我们需要将这两个void指针强制转换为我们实际数据类型的指针,然后根据具体的需求进行比较操作。例如,对于整数数组的升序排序,比较函数可以定义为:
int compare(const void *a, const void *b) {int arg1 = *(const int*)a;int arg2 = *(const int*)b;if(arg1 == arg2) return 0;return arg1 < arg2 ? -1 : 1;
}
这里,我们将传入的void指针转换为int指针,然后比较两个整数的大小。如果arg1小于arg2,返回-1,表示a应该排在b前面;如果arg1大于arg2,返回1,表示a应该排在b后面;如果两者相等,返回0。
(三)使用示例
假设我们有一个整数数组,想要使用qsort函数对其进行升序排序:
#include <stdio.h>
#include <stdlib.h>int compare(const void *a, const void *b) {int arg1 = *(const int*)a;int arg2 = *(const int*)b;if(arg1 == arg2) return 0;return arg1 < arg2 ? -1 : 1;
}int main() {int arr[] = {5, 3, 8, 1, 2, 7, 4, 6};int n = sizeof(arr) / sizeof(arr[0]);printf("Before sorting:\n");for(int i = 0; i < n; i++) {printf("%d ", arr[i]);}printf("\n");qsort(arr, n, sizeof(int), compare);printf("After sorting:\n");for(int i = 0; i < n; i++) {printf("%d ", arr[i]);}printf("\n");return 0;
}
运行结果为:
Before sorting:
5 3 8 1 2 7 4 6
After sorting:
1 2 3 4 5 6 7 8
在这个例子中,我们通过定义比较函数compare,将升序排序的规则传递给qsort函数,从而实现了对整数数组的排序操作。
三、qsort函数的模拟实现(冒泡排序)
(一)基本思路
冒泡排序是一种简单的排序算法,它重复地遍历要排序的数组,比较每对相邻元素,如果它们的顺序错误就把它们交换过来。遍历数组的工作是重复地进行直到没有再需要交换的元素,也就是说该数组已经排序完成。
从零开始学习冒泡排序,忘记的可以先看看这篇文章。
(二)模拟qsort函数的实现
为了模拟qsort函数的行为,我们需要考虑其通用性,即能够对不同类型的数据进行排序。因此,我们需要使用void指针来处理数据,并通过比较函数指针来定义排序规则。以下是使用冒泡排序算法模拟实现的代码:
void my_qsort(void *base, size_t num, size_t width, int (*comp)(const void *, const void*)) {char *arr = (char*)base; // 将基地址转换为字符指针,方便操作for(size_t i = 0; i < num - 1; i++) {for(size_t j = 0; j < num - i - 1; j++) {// 比较相邻元素if(comp(arr + j * width, arr + (j + 1) * width) > 0) {// 交换元素for(size_t k = 0; k < width; k++) {char temp = arr[j * width + k];arr[j * width + k] = arr[(j + 1) * width + k];arr[(j + 1) * width + k] = temp;}}}}
}
(三)测试模拟实现
为了验证我们模拟实现的my_qsort函数是否正确,可以使用与之前相同的测试用例:
int main() {int arr[] = {5, 3, 8, 1, 2, 7, 4, 6};int n = sizeof(arr) / sizeof(arr[0]);printf("Before sorting:\n");for(int i = 0; i < n; i++) {printf("%d ", arr[i]);}printf("\n");my_qsort(arr, n, sizeof(int), compare);printf("After sorting:\n");for(int i = 0; i < n; i++) {printf("%d ", arr[i]);}printf("\n");return 0;
}
运行结果与使用标准库的qsort函数相同,说明我们的模拟实现是正确的。
总结
通过本文的探讨,我们深入了解了回调函数的概念及其在C语言中的应用,重点分析了qsort函数的使用方法和工作原理,并成功使用冒泡排序算法模拟实现了该函数。这一过程不仅加深了我们对指针、函数指针以及冒泡排序算法的理解,还提高了我们的编程实践能力。在实际开发中,灵活运用回调函数和qsort等标准库函数,可以大大提高代码的可读性、可维护性和效率。希望读者能够通过本文的学习,在C语言的指针世界中更进一步,为后续的学习和工作打下坚实的基础。
相关文章:
深入理解指针(4)(C语言版)
文章目录 前言一、回调函数是什么(一)定义(二)工作原理(三)应用场景 二、qsort举例(一)qsort函数简介(二)比较函数的定义(三)使用示例…...
【 <二> 丹方改良:Spring 时代的 JavaWeb】之 Spring Boot 中的日志管理:Logback 的集成
<前文回顾> 点击此处查看 合集 https://blog.csdn.net/foyodesigner/category_12907601.html?fromshareblogcolumn&sharetypeblogcolumn&sharerId12907601&sharereferPC&sharesourceFoyoDesigner&sharefromfrom_link <今日更新> 一、开篇整…...
记录一次渗透测试/常用命令
渗透测试常用命令速览:从扫描到提权再到流量劫持 在渗透测试中,命令行工具是我们的得力助手。本文总结了我最近在测试虚拟机靶机(IP: 192.168.73.129)时用到的主要命令,涵盖网络扫描、暴力破解、权限提升、数据修改和…...
C++11QT复习(二)
文章目录 Day4-4 New 与 delete 表达式(2025.03.20)1. new 表达式的三个步骤2. delete 表达式的两个步骤3. new[] 与 delete[] Day5 类的定义和关键字再探(2025.03.24)1. C 关键字 const、static、extern2. 类的定义:C…...
Pytorch学习笔记(十)Learning PyTorch - Learning PyTorch with Examples
这篇博客瞄准的是 pytorch 官方教程中 Learning PyTorch 章节的 Learning PyTorch with Examples 部分。 官网链接:https://pytorch.org/tutorials/beginner/pytorch_with_examples.html 完整网盘链接: https://pan.baidu.com/s/1L9PVZ-KRDGVER-AJnXOvlQ?pwdaa2m…...
如何使用DeepSeek编写测试用例?
一、DeepSeek在测试用例设计中的定位 DeepSeek作为AI工具,并非直接替代测试设计,而是通过以下方式提升效率: 快速生成基础用例框架(等价类、边界值等) 智能补充易遗漏场景(如特殊字符、异常流) 自动化脚本片段生成(Python/pytest/JUnit等) 测试数据构造建议(符合业务…...
sql server如何提高索引命中率
#新星杯14天创作挑战营第9期# 前言 近期发现以前开发的系统运行缓慢,经排查,发现有很大的优化空间。数据库版本使用的是sql server,主要有以下一些问题点:数据表无索引、一些不规范的写法(例如in、大表关联࿰…...
FALL靶机
下载靶机,可以看到靶机地址 在kali上扫描靶机的端口和目录文件 访问:http://192.168.247.146/test.php,他提示我们参数缺失 我们爆破一下他的参数 使用kali自带的fuzz FUZZ就是插入参数的位置 -w 指定字典文件 wfuzz -u "http://192.…...
北斗导航 | 改进最小二乘残差法的接收机自主完好性监测算法原理,公式,应用,研究综述,matlab代码
改进最小二乘残差法的接收机自主完好性监测算法研究 摘要 本文针对传统最小二乘残差RAIM算法在复杂环境下检测性能不足的问题,提出了一种基于加权抗差估计的改进算法。通过引入IGGⅢ权函数构建抗差最小二乘模型,结合滑动窗口方差估计和自适应阈值调整机制,显著提升了算法对…...
WPF 浅述ToolTipService.ShowOnDisabled
WPF 浅述ToolTipService.ShowOnDisabled ToolTipService.ShowOnDisabled 属性可以让工具提示在控件禁用状态下仍然显示。这是一个非常方便且简洁的方式。 使用 ToolTipService.ShowOnDisabled,你可以通过设置 ToolTipService.ShowOnDisabled 属性来确保即使在控件禁…...
嵌入式硬件工程师从小白到入门-PCB绘制(二)
PCB绘制从小白到入门:知识点速通与面试指南 一、PCB设计核心流程 需求分析 明确电路功能(如电源、信号处理、通信)。确定关键参数(电压、电流、频率、接口类型)。 原理图设计 元器件选型:匹配封装、电压、…...
05 Python 元组:不可变序列的解析和应用
文章目录 前言元组定义元组的运算索引操作切片操作连接和重复运算循环遍历元组中的元素成员运算内置函数运算 打包和解包操作交换变量的值 前言 在 Python 编程领域,元组(Tuple)是一类极为重要的数据结构。它属于不可变的序列类型࿰…...
MATLAB 批量移动 TIF 文件至分类文件夹
文章目录 前言一、步骤二、代码 前言 本代码用于从指定的源文件夹 (sourceFolder) 中筛选所有 .tif 文件,并根据文件名的特定关键词(Daynight 和 FDI)将其分类移动到相应的目标文件夹 (targetDaynightFolder 和 targetFDIFolder)。 一、步骤…...
Milvus×最新版DeepSeek v3:对标Claude,本地数据五分钟写网站
前言 就在昨晚,DeepSeek v3推出了新版本V3-0324,再次一夜爆火。 虽然官方表示“这只是一次小升级”“API接口和使用方式不变”,但经过Zilliz的第一时间实测,我们发现无论是逻辑能力,还是编程能力,相较原本的…...
抽象代数:群论
系列笔记为本学期上抽象代数课整理的,持续更新。 群的相关定义 群的定义 群是一个带有满足结合律、单位元、逆元的二元运算的集合,记作 ( G , ⋅ ) \left({G, \cdot}\right) (G,⋅)。若群运算满足结合律,则该集合构成半群。如果该半群中含…...
基于 mxgraph 实现流程图
mxgraph 可以实现复杂的流程图绘制。mxGraph里的Graph指的是图论(Graph Theory)里的图而不是柱状图、饼图和甘特图等图(chart),因此想找这些图的读者可以结束阅读了。 作为图论的图,它包含点和边,如下图所示。 交通图 横道图 架构图 mxGrap…...
Stereolabs ZED Box Mini:机器人与自动化领域的人工智能视觉新选择
在人工智能视觉技术快速发展的今天,其应用场景正在持续拓宽,从智能安防到工业自动化,从机器人技术到智能交通,各领域都在积极探索如何利用这一先进技术。而 Stereolabs 推出的ZED Box Mini,正是一款专为满足这些多样化…...
音视频 二 看书的笔记 MediaPlayer
此类是用于播放声音和视频的主要 API 对方不想多说向你丢了一个链接 MediaPlayer Idle 空闲状态Initialized 初始化状态 调用 setDataSource() 时会进入此状态 setDataSource必须在Idle 状态下调用,否则就抛出异常了了了了了。Prepared 准备状态 回调监听setOnPrep…...
可以把后端的api理解为一个目录地址,但并不准确
将后端的 API 理解为一个“目录地址”是可以的,但并不完全准确。让我们更详细地解释一下。 目录 1、生动形象了解api 2、后端 API 的作用 3、可以将 API 理解为“目录地址”的原因 (1)URL 路径 (2)层次结构 4、…...
vscode连接服务器失败问题解决
文章目录 问题描述原因分析解决方法彻底删除VS Code重新安装较老的版本 问题描述 vscode链接服务器时提示了下面问题: 原因分析 这是说明VScode版本太高了。 https://code.visualstudio.com/docs/remote/faq#_can-i-run-vs-code-server-on-older-linux-distribu…...
Qt 高效读写JSON文件,玩转QJsonDocument与QJsonObject
一、前言 JSON作为轻量级的数据交换格式,已成为开发者必备技能。Qt框架为JSON处理提供了完整的解决方案,通过QJsonDocument、QJsonObject和QJsonArray三大核心类,轻松实现数据的序列化与反序列化。 JSON vs INI 特性JSONINI数据结构支持嵌…...
开源视频剪辑工具,无损编辑更高效
LosslessCut 是一款基于 FFmpeg 开发的跨平台开源视频剪辑工具,致力于无损处理音视频文件。它无需重新编码即可完成剪切、合并、轨道编辑等操作,极大地保留了原始文件的质量,特别适合处理大体积视频,如无人机拍摄素材或长时录制内…...
Git 之配置ssh
1、打开 Git Bash 终端 2、设置用户名 git config --global user.name tom3、生成公钥 ssh-keygen -t rsa4、查看公钥 cat ~/.ssh/id_rsa.pub5、将查看到的公钥添加到不同Git平台 6、验证ssh远程连接git仓库 ssh -T gitgitee.com ssh -T gitcodeup.aliyun.com...
(UI自动化测试web端)第二篇:元素定位的方法_css定位之ID选择器
看代码里的【find_element_by_css_selector( )】( )里的表达式怎么写? 文章介绍了第一种写法id选择器,其实XPath元素定位要比CSS好用,原因是CSS无法使用下标(工作当中也是常用的xpath),但CSS定位速度比XPat…...
Mysql---锁篇
1:MySQL 有哪些锁? 全局锁 flush tables with read lock 整个数据库就处于只读状态了 unlock tables 释放全局锁 全局锁主要应用于做全库逻辑备份,这样在备份数据库期间,不会因为数据或表结构的更新,而出现备份文件的数…...
Django 项目打包exe本地运行
Django 项目打包exe本地运行 记一次离谱的需求 其实本来觉得Django项目架构比较清晰,代码逻辑也简单,没打算记笔记,结果遇到离谱需求折腾了很久 开发了一个Django项目,到交付的时候了,客户说自己没有服务器… 没服务器还要登录功能😓 没办法,甲方最大,整吧 第一…...
20250330 Pyflink with Paimon
1. 数据湖 2. 本地安装Pyflink和Paimon 必须安装Python 3.11 Pip install python -m pip install apache-flink1.20.1 需要手动加入这两个jar 测试代码: import argparse import logging import sys import timefrom pyflink.common import Row from pyflink.tab…...
RTMP推流服务器nginx在linux上的编译部署
RTMP(Real-Time Messaging Protocol)推流确实需要服务器支持。RTMP推流服务器的主要功能是接收来自推流客户端的数据流,对其进行处理和转发。服务器会根据RTMP协议与客户端建立连接,处理推流数据(如转码、录制等&…...
Matlab教程001:软件介绍和界面使用
1.1 软件介绍 1.1.1 Matlab的介绍 MATLAB(MATrix LABoratory)是一款由 MathWorks 公司开发的高级编程语言和交互式环境,广泛用于 科学计算、数据分析、机器学习、工程建模、仿真和信号处理 等领域。 1.1.2 主要应用领域 数据分析与可视化…...
【SQL Server数据库备份详细教程】
🎥博主:程序员不想YY啊 💫CSDN优质创作者,CSDN实力新星,CSDN博客专家 🤗点赞🎈收藏⭐再看💫养成习惯 ✨希望本文对您有所裨益,如有不足之处,欢迎在评论区提出…...
Java设计模式之解释器模式
概念 解释器模式是一种行为型设计模式,用于定义一种语言的语法规则,并提供解释器来解释该语言中的表达式。 作用 其核心作用是将复杂的语法分解为简单的语法单元,通过递归组合的方式构建抽象语法树(AST),…...
el-date-picker时间范围 编辑回显后不能修改问题
el-date-picker daterange时间范围 编辑回显后不能修改 <el-form-item:label"LABELS.gplanRecordDateLabel"prop"gplanRecordDate"><el-date-pickerstyle"width: 300px"v-model"formData.gplanRecordDate"type"daterang…...
vue复习1~45
1.关于vue 要理解记忆规则,可以到官网上去找 vue的两种使用方式 vue核心包开发 场景:局部模块改造vue核心包 & vue插件 工程化开发 场景:整站开发 2.创建vue实例 构建用户页面->创建vue实例初始化渲染 学习阶段用开发版本 3.插值…...
Servlet开发与生命周期详解-2
一、在集成开发环境当中开发Servlet程序 1.集成开发工具很多,其中目前使用比较多的是: IntelliJ IDEA(这个居多,IDEA在提示功能方面要强于Eclipse,也就是说IDEA使用起来比Eclipse更加智能,更好用。JetBrai…...
vue2项目eslint提示<template v-for> key should be placed on the <template> tag
在template标签上使用v-for时,vue2会提示key不可放在template标签上,必须放在子元素上。vue3会提示key必须放在template标签上。这时候可能我们怎么写都会触发eslint校验提醒。不影响使用,但看着难受。 我们可以在根目录上新建jsconfig.json…...
老是忘记package.json,备忘一下 webpack 环境下 Vue Cli 和 Vite 命令行工具对比
Vue 2.X webpack 环境下 Vue Cli 的命令 "scripts": {"dev": "vue-cli-service serve","prod": "vue-cli-service serve --mode production","build:dev": "vue-cli-service build --mode development"…...
关于跨域问题(本地前端访问服务器端接口跨域出错)
问题来源: 当服务器封装了接口但是本地电脑端前端访问出现跨域问题。 解决方案; 1、使用ipconfig 查看本地电脑的ip地址 ipconfig 2、在后端接口处配置如下代码 allow_origins["http://本地ip地址:3001", # 局域网内其他设备访问的本地…...
Jackson相关问题
1、json转dto的时候,dto不能定义isActive这种带有is的前缀,如果使用Lombok的Getter/Setter的话,json {"isActive": true},这样,将无法正确赋值。此时的dto再次转为json之后,得到的是active:false…...
【C++】互斥锁(Mutex)和原子操作(Atomics)
详细探讨 C 中的并发、多线程、互斥锁(Mutex)和原子操作(Atomics)的概念及其区别,并附带代码示例。 1. C 并发与多线程 (Concurrency vs. Multithreading) 并发 (Concurrency):指系统能够处理多个任务的能…...
Linux--命令行操作
一、Linux的作用 1.简单的文件操作 2.编程 3.支持系统和网络 二、多账号管理 1、我们需要在root账号下进行,可以用whoami来查询账号身份 2、adduser 你要创建的账号名 就可以创建一个账号 3、ls /home可以查看账号是否创立 4、使用passwd 创建账号名字的来设…...
具身系列——Diffusion Policy算法实现CartPole游戏
代码原理分析 1. 核心思想 该代码实现了一个基于扩散模型(Diffusion Model)的强化学习策略网络。扩散模型通过逐步去噪过程生成动作,核心思想是: • 前向过程:通过T步逐渐将专家动作添加高斯噪声,最终变成…...
4.用 Excel 录入数据
一 用 Excel 录入数据的两种方式 用鼠标键盘录入数据和从网上爬取数据。 二 用鼠标键盘录入数据 1.录入数据的规范 横着录入数据(横着一条条录入数据)。 2.使用快捷键进行数据录入 tab 键和 enter 键。 tab 键:向右移动一个单元格。 tab 键…...
nginx配置跳转设置Host有误导致报404问题
我们有个项目,前端调用了第三方接口。为了避免跨域,所以使用nginx进行转发。一直正常工作,相安无事。近日第三方调整了安全策略,http转换成https,原本使用ip,现在也改成使用域名,所以nginx这里我…...
接口/UI自动化面试题
一、UI自动化 1.1、接口和UI自动化有多少用例? 回答策略:根据接口设定用例,100个接口,自动化case在1500-2000左右。结合自身的项目,回答覆盖的主功能流程。 示例: 接口自动化的测试case一般需要根据接口数…...
Java 中调用语言模型(如 OpenAI、阿里云通义千问、Hugging Face 等)API 的详细步骤和示例代码,涵盖常见场景及注意事项
以下是 Java 中调用语言模型(如 OpenAI、阿里云通义千问、Hugging Face 等)API 的详细步骤和示例代码,涵盖常见场景及注意事项: 1. 常见语言模型 API 选择 (1) OpenAI API 特点:支持 GPT-3、GPT-3.5、GPT-4 等模型&a…...
搜广推校招面经六十
soul推荐算法 一、word2vec原理 参考一篇文章入门Word2Vec 二、word2vec正负采样怎么做的、word2vec采用的loss和原理 见【搜广推校招面经四、搜广推校招面经五十二、搜广推校招面经五十七】 不太理解为啥问这么多word2vec,索性直接整理一遍。 三、多路召回融合…...
红宝书第十二讲:详解JavaScript中的工厂模式与原型模式等各种设计模式
红宝书第十二讲:详解JavaScript中的工厂模式与原型模式等各种设计模式 资料取自《JavaScript高级程序设计(第5版)》。 查看总目录:红宝书学习大纲 工厂模式和原型模式解析 一、工厂模式:像订外卖一样创建对象 工厂模…...
Flutter完整开发实战详解(一、Dart语言和Flutter基础)
前言 在如今的 Flutter 大潮下,本系列是让你看完会安心的文章。本系列将完整讲述:如何快速从0开发一个完整的 Flutter APP,配套高完成度 Flutter 开源项目 GSYGithubAppFlutter。同时也会提供一些 Flutter 的开发细节技巧,并针对…...
Kafka 偏移量
在 Apache Kafka 中,偏移量(Offset)是一个非常重要的概念。它不仅用于标识消息的位置,还在多种场景中发挥关键作用。本文将详细介绍 Kafka 偏移量的核心概念及其使用场景。 一、偏移量的核心概念 1. 定义 偏移量是一个非负整数…...
手撕LRU缓存Java版(带输入输出)
由于面试手撕lru没撕出来,导致心态炸裂,今天特地练习了lru输入输出 手撕版,在每个函数里手动加上输出 public class LC146 {static class LRUCache{class Node{int key, value;Node prev, next;Node(int key, int value){this.key key;thi…...