当前位置: 首页 > article >正文

深入理解指针(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语言版)

文章目录 前言一、回调函数是什么&#xff08;一&#xff09;定义&#xff08;二&#xff09;工作原理&#xff08;三&#xff09;应用场景 二、qsort举例&#xff08;一&#xff09;qsort函数简介&#xff08;二&#xff09;比较函数的定义&#xff08;三&#xff09;使用示例…...

【HTML】验证与调试工具

个人主页&#xff1a;Guiat 归属专栏&#xff1a;HTML CSS JavaScript 文章目录 1. HTML 验证工具概述1.1 验证的重要性1.2 常见 HTML 错误类型 2. W3C 验证服务2.1 W3C Markup Validation Service2.2 使用 W3C 验证器2.3 验证结果解读 3. 浏览器开发者工具3.1 Chrome DevTools…...

【Mysql】SQL 优化全解析

文章目录 一、理解执行计划​1.1 执行计划的作用​1.2 查看执行计划​ 二、查询优化​2.1 避免全表扫描​2.2 使用覆盖索引​2.3 合理使用 JOIN​ 三、索引优化​3.1 索引设计原则​3.2 索引维护​ 在数据驱动的当今时代&#xff0c;MySQL 作为应用广泛的开源关系型数据库&…...

​​SenseGlove与Aeon Robotics携手推出HEART项目,助力机器人培训迈向新台阶

在自动化和机器人技术快速发展的今天&#xff0c;SenseGlove和Aeon Robotics联合推出了一项创新项目——HEART项目。该项目在欧盟资助的MasterXR框架内展开&#xff0c;旨在通过整合虚拟现实&#xff08;VR&#xff09;、力反馈触觉手套&#xff08;SenseGlove项目Rembrandt&am…...

mapbox进阶,仿照百度,加载marker点位,移入marker点切换图标,点击展示气泡,气泡和marker联动

👨‍⚕️ 主页: gis分享者 👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.2 ☘️mapboxgl.Map style属性1.3 ☘️marker 标注点位 api1.3.1 ☘️构造函数…...

使用HTML5和CSS3实现3D旋转相册效果

使用HTML5和CSS3实现3D旋转相册效果 这里写目录标题 使用HTML5和CSS3实现3D旋转相册效果项目介绍技术栈核心功能实现思路1. HTML结构2. CSS样式解析2.1 基础样式设置2.2 3D效果核心样式2.3 卡片样式 3. JavaScript交互实现3.1 旋转控制3.2 自动播放功能 技术要点总结项目亮点总…...

HTML5 新的 Input 类型学习笔记

HTML5 引入了多种新的表单输入类型&#xff0c;这些新特性不仅增强了输入控制&#xff0c;还提供了更强大的验证功能&#xff0c;使表单设计更加灵活和便捷。以下是 HTML5 新的 Input 类型的详细学习笔记。 一、color 类型 功能&#xff1a;用于选取颜色。 使用场景&#xff…...

游戏引擎学习第186天

回顾并规划今天的任务 现在&#xff0c;我们站在了一个关键的时刻&#xff0c;准备突破&#xff0c;拥有一些优秀的性能分析代码。从目前来看&#xff0c;我们已经能够看到时间的消耗情况&#xff0c;我对这一点感到非常兴奋。昨天的直播中我们勉强让一些东西工作了&#xff0…...

NDK CMake工程中引入其他C++三方库

在Android NDK CMake工程中引入其他C三方库时&#xff0c;有以下几种常见的依赖方式&#xff1a; 1. 源码依赖 如果三方库的源代码包含在你的项目目录中&#xff0c;并且它有自己的CMake配置&#xff0c;可以使用add_subdirectory将三方库的构建过程集成到你的项目中。 示例…...

【redis】持久化之RDB与AOF

在数字世界的脉搏中&#xff0c;数据是流淌的血液&#xff0c;而持久化则是保障系统生命力的核心机制。作为内存数据库的标杆&#xff0c;Redis凭借其高性能特性成为互联网架构的基石&#xff0c;但其「易失性」的天然属性也催生了关键命题&#xff1a;如何在服务重启或故障时保…...

Brainstorm绘制功能连接图(matlab)

上篇笔记简单介绍了Brainstorm&#xff0c;本次使用Brainstorm绘制功能连接图。而对于连接矩阵&#xff0c;软件中有几种方法&#xff1a;相关、相干、双变量格兰杰因果关系、相位锁相值、包络相关、相位转移熵。 首先&#xff0c;对数据进行预处理&#xff0c;保存为.set&…...

华为HG532路由器RCE漏洞 CVE-2017-17215 复现

华为HG532路由器RCE漏洞 CVE-2017-17215 CVE-Description Huawei HG532 with some customized versions has a remote code execution vulnerability. An authenticated attacker could send malicious packets to port 37215 to launch attacks. Successful exploit could l…...

CSS3学习教程,从入门到精通,CSS3 弹性盒子(Flexbox)布局全面指南(20)

CSS3 弹性盒子(Flexbox)布局全面指南 一、Flexbox 概述 Flexbox&#xff08;弹性盒子&#xff09;是 CSS3 提供的一种一维布局模型&#xff0c;可以轻松实现各种复杂的页面布局。它特别适合处理不同屏幕尺寸下的元素排列和对齐问题。 主要优势&#xff1a; 简单实现垂直居中…...

Redis 性能数据解读与问题排查优化版

目录标题 Redis 性能数据解读与问题排查优化版一、Redis 性能数据解读二、常见问题排查与解决&#xff08;一&#xff09;CPU 使用率高&#xff08;二&#xff09;内存使用异常&#xff08;三&#xff09;集群状态异常&#xff08;四&#xff09;数据库状态问题 三、综合优化建…...

新能源动力电池测试设备深度解析:充放电设备与电池模拟器的差异及技术趋势

一、技术原理对比与核心技术创新 充放电设备 核心原理与硬件架构 充放电设备的核心功能是通过电力电子技术精确控制电池的充放电过程&#xff0c;其硬件架构包括高精度电源模块、双向DC/DC变换器、数据采集系统和温控单元。例如&#xff0c;在放电阶段&#xff0c;设备通过双向…...

LVS的三种工作模式简述

一、引言 在过去的十几年中&#xff0c;Internet从几个研究机构相连为信息共享的网络发展成为拥有大量应用和服务的全球性网络&#xff0c;它正成为人们生活中不可缺少的 一部分。虽然Internet发展速度很快&#xff0c;但建设和维护大型网络服务依然是一项挑战性的任务&#xf…...

Ribbon负载均衡的深度解析与应用

在微服务架构中&#xff0c;服务之间的调用频繁且复杂&#xff0c;因此负载均衡显得尤为重要。Spring Cloud生态系统中&#xff0c;Ribbon作为一个客户端负载均衡器&#xff0c;扮演着关键的角色。它不仅能提高系统的响应速度&#xff0c;还能确保系统的稳定性和可用性。接下来…...

使用 Layers 扩展你的 Nuxt4 应用

面对一个臃肿的页面或项目&#xff0c;你会如何简化重构、扩展它&#xff1f; 当单个 Vue 文件中界面/业务足够多时&#xff0c;通常我们会把它拆分成多个 components 或 composables 来引入&#xff0c;以此来减少此文件复杂度和增加可维护性。 当一个项目的界面/业务逻辑足…...

Excel处理控件Aspose.Cells指南:如何在不使用 Microsoft Excel 的情况下解锁 Excel 工作表

Microsoft Excel 允许用户使用密码保护工作表&#xff0c;以防止未经授权的更改。但是&#xff0c;在某些情况下&#xff0c;您可能需要在不使用 Microsoft Excel 的情况下解锁 Excel 工作表。在本指南中&#xff0c;我们将探讨解锁 Excel 工作表的不同方法&#xff0c;例如使用…...

进军场景智能体,云迹机器人又快了一步

&#xff08;图片来源&#xff1a;Pixels&#xff09; 2025年&#xff0c;AI和机器人行业都发生了巨大改变。 数科星球原创 作者丨苑晶 编辑丨大兔 2025年&#xff0c;酒店行业正掀起一股批量采购具备AI功能的软硬一体解决方案的热潮。 在DeepSeek、Manus等国产AI软件的推动…...

vue 使用v-model实现父子组件传值——子父组件同步更新

基于vue2和vue3两个版本的框架略显不同&#xff0c;所以我分开的来讲&#xff1a; 1、vue2 子组件&#xff08;my-input.vue&#xff09;&#xff1a; <template><input type"text" :value"name" input"inputChange" /> </tem…...

PHP 应用SQL 注入符号拼接请求方法HTTP 头JSON编码类

#PHP-MYSQL- 数据请求类型 SQL 语句由于在黑盒中是无法预知写法的&#xff0c; SQL 注入能发成功是需要拼接原 SQL 语句&#xff0c; 大部分黑盒能做的就是分析后各种尝试去判断&#xff0c;所以有可能有注入但可能出现无法注入成 功的情况。究其原因大部分都是原 SQL …...

【React】基础版React + Redux实现教程,自定义redux库,Redux Toolkit教程

本项目是一个在react中&#xff0c;使用 redux 管理状态的基础版实现教程&#xff0c;用简单的案例练习redux的使用&#xff0c;旨在帮助学习 redux 的状态管理机制&#xff0c;包括 store、action、reducer、dispatch 等核心概念。 项目地址&#xff1a;https://github.com/Yv…...

23种设计模式-适配器(Adapter)设计模式

适配器设计模式 &#x1f6a9;什么是适配器设计模式&#xff1f;&#x1f6a9;适配器设计模式的特点&#x1f6a9;适配器设计模式的结构&#x1f6a9;适配器设计模式的优缺点&#x1f6a9;适配器设计模式的Java实现&#x1f6a9;代码总结&#x1f6a9;总结 &#x1f6a9;什么是…...

debug 笔记:llama 3.2 部署bug 之cutlassF: no kernel found to launch!

1 问题描述 按照官方的写法 import torch from transformers import pipeline import os os.environ["HF_TOKEN"] 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 model_id "meta-llama/Llama-3.2-3B"pipe pipeline("text-generation", modelmode…...

TCP的长连接和短连接,以及它们分别适用于什么场合

TCP长连接与短连接详解 一、核心概念对比 特性长连接&#xff08;Persistent Connection&#xff09;短连接&#xff08;Short-lived Connection&#xff09;连接生命周期一次建立后长期保持&#xff0c;多次数据交互复用同一连接每次数据交互均需新建连接&#xff0c;完成后…...

【操作系统】(五)操作系统引导(Boot)

视频参考&#xff1a;王道计算机2.了解计算机的启动过程和主引导扇区&#xff0c;让你的计算机从这里起飞吧_哔哩哔哩_bilibili 操作系统引导(Boot)就是在开机的时候&#xff0c;如何让操作系统运行起来&#xff1f; 主存分成RAM小部分ROM,其中ROM里面存放的是BIOS&#xff08…...

蓝桥与力扣刷题(蓝桥 山)

题目&#xff1a;这天小明正在学数数。 他突然发现有些止整数的形状像一挫 “山”, 比㓚 123565321、145541123565321、145541, 它 们左右对称 (回文) 且数位上的数字先单调不减, 后单调不增。 小朋数了衣久也没有数完, 他惒让你告诉他在区间 [2022,2022222022] 中有 多少个数…...

211数学专业大三想转码C++方向,目前在学算法,没系统学习计算机专业课,要先定方向吗?

今天给大家分享的是一位粉丝的提问&#xff0c;211数学专业大三想转码C方向&#xff0c;目前在学算法&#xff0c;没系统学习计算机专业课&#xff0c;要先定方向吗&#xff1f; 接下来把粉丝的具体提问和我的回复分享给大家&#xff0c;希望也能给一些类似情况的小伙伴一些启…...

场馆预约小程序的设计与实现

摘 要 时代在进步&#xff0c;人们对日常生活质量的要求不再受限于衣食住行。现代人不仅想要一个健康的身体&#xff0c;还想拥有一身宛如黄金比例的身材。但是人们平常除了上下班和上下学的时间&#xff0c;其余空余时间寥寥无几&#xff0c;所以我们需要用体育场馆预约来节省…...