深入解剖指针(4)

个人主页(找往期文章包括但不限于本期文章中不懂的知识点): 我要学编程(ಥ_ಥ)-CSDN博客

目录

回调函数

qsort使用举例

使用qsort函数排序整型数据 

使用qsort排序结构数据 

qsort函数的模拟实现 


 

回调函数

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

简单来说就是:当我拥有一个函数(地址)指针时,在一些特定的情况下,通过函数指针回过头来调用这个函数,那么这个被调用的函数就是回调函数。

在简易计算器的制作(函数指针数组的实践)-CSDN博客这篇文章中写的计算代码,就是可以用这个回调函数的例子。如果我们要使用加法计算两个数的值,不是直接由main函调用的,而是由calc函数来调用对应的加法函数。这便是回调函数。

qsort使用举例

使用qsort函数排序整型数据 

如果我们想要排序一组数据,按照升序或者降序的方式,首先想到的就是冒泡排序。这个排序在深入解剖指针篇(2)-CSDN博客 这篇文章中介绍了。核心思想就是:两两相邻元素的比较。

我们现在就用qsort函数来实现。首先,就得了解什么是qsort函数。

上面就是关于qsort函数的基本介绍。

void qsort(void* base, //这个base就是要排序的元素的起始地址size_t num, //这个num就是要排序的元素个数size_t size,//这个size就是要排序的元素对应字节数int (*compar)(const void*, const void*));//这个其实就是一个 有比较功能函数 的指针

上面那个比较功能就是你要怎么实现这个排序,就用什么功能。例如:我要实现升序功能,那么这个函数就是实现升序的功能。 

我们现在就可以开始模拟实现冒泡排序了。

#include <stdio.h>
#include <stdlib.h>//qsort函数所需的头文件//打印数据看看是否排序成功
void Print(int arr[], int sz)
{for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}
}//调用的排序函数
//由于创造这个函数的人,不知道我们会比较什么样的数据,因此,就要void*来接收。
int int_cmp(const void* p1, const void* p2)
{//qsort默认的是升序,由于void*不能直接解引用,所以就先得强制转换为要比较(int*)的数据类型return (*(int*)p1 - *(int*)p2);//如果我们像排成降序,就可以把这个给反过来
}int main()
{int arr[] = { 9,8,7,6,5,4,3,2,1,0 };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), int_cmp);Print(arr, sz);return 0;
}

可以看出来这个qsort函数排序是正确的。

使用qsort排序结构数据 

我们假设要排序一些不是整型的数据,那么冒泡排序肯定是不行的。但是我们可以采用其思想,来进行排序。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct stu//创建一个结构体类型:学生
{char name[20];int age;
};int cmp_stu_by_name(const void* e1, const void* e2)
{return strcmp(((struct stu*)e1)->name, ((struct stu*)e2)->name);
}void Print(struct stu* p, int sz)
{for (int i = 0; i < sz; i++){printf("%s ", (p+i)->name);//结构体指针->成员名}printf("\n");
}
int main()
{//创建一个结构体数组并且初始化struct stu arr[] = { {"zhangsan", 20},{"lisi" ,30}, {"wangwu", 18} };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);Print(arr, sz);return 0;
}

 strcmp是用来比较字符串大小的,具体用法请看:字符函数与字符串函数(上)-CSDN博客 

通过上面的学习,我们就可以发现这个qsort函数在使用时,需要我们根据自己的需求来写出对应的比较函数。

结构体成员的间接访问 

我们在访问结构体成员时,有两种操作符,一种是 . (直接访问),还有一种是 ->(间接访问)。

直接访问在操作符详解(下)-CSDN博客 里讲过。

结构体指针->成员名 ,即当 -> 的左边满足时结构体指针时,我们要访问结构体成员就可以用->。 

上面是排序其名字,我们还可以排序其年龄

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct stu
{char name[20];int age;
};int cmp_stu_by_age(const void* e1, const void* e2)
{return (((struct stu*)e1)->age - ((struct stu*)e2)->age);
}void Print(struct stu* p, int sz)
{for (int i = 0; i < sz; i++){printf("%d ", (p + i)->age);}printf("\n");
}int main()
{struct stu arr[] = { {"zhangsan", 20},{"lisi" ,30}, {"wangwu", 18} };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);Print(arr, sz);return 0;
}

qsort函数的模拟实现 

我们现在就来通过模拟实现qsort函数(用冒泡的方式)来排序整形数组。

#include <stdio.h>
int cmp(const void* e1, const void* e2)
{return *(int*)e1 - *(int*)e2;
}//因为前面有强制转换为char*了,所以我们也就不用void*了
void Swap(char* p1, char* p2, size_t width)
{//如果是排序char的数据,我们就只能一个字节一个字节的交换for (int i = 0; i < width; i++){char tmp = *(p1+i);*(p1+i) = *(p2+i);*(p2+i) = tmp;}
}void bubble_sort(void* base, size_t num, size_t width, int(*cmp)(void*, void*))
{for (int i = 0; i < num - 1; i++){for (int j = 0; j < num - 1 - i; j++){//如果前者大于后者,也就是降序,会返回一个大于0的数(根据这个cmp的函数来的)//不知道是啥类型,强制转换为最小的就行(类型占字节最小的是字符型)if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0){//交换Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);}}}
}int main()
{int arr[] = { 9,8,7,6,5,4,3,2,1,0 };int sz = sizeof(arr) / sizeof(arr[0]);bubble_sort(arr, sz, sizeof(arr[0]), cmp);//采用冒泡的方式for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}printf("\n");return 0;
}

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

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

相关文章

《Spring Security 简易速速上手小册》第10章 未来趋势与高级话题(2024 最新版)

文章目录 10.1 云原生安全性趋势10.1.1 基础知识10.1.2 重点案例&#xff1a;保护微服务通信10.1.3 拓展案例 1&#xff1a;容器安全最佳实践10.1.4 拓展案例 2&#xff1a;自动化安全审计和合规性检查 10.2 反应式编程与 Spring Security10.2.1 基础知识10.2.2 重点案例&#…

nginx-图片模块

./configure --with-http_image_filter_module location / {root html;index index.html index.htm;if ($arg_w "") {set $arg_w -;}if ($arg_h "") {set $arg_h -;}image_filter resize $arg_w $arg_h;image_filter_jpeg_quality 95; } 访问: 1234…

CSS锥形渐变:conic-gradient()

画一个扇形图&#xff0c;使用常规方法可能很难画&#xff0c;但是用锥形渐变的话非常好画 <style>.pattern{width: 100px; height: 100px;border-radius: 50%;background: conic-gradient(yellow 30deg , black 30deg , black 90deg , yellow 90deg ,yellow 150d…

Git分布式版本控制系统——git学习准备工作

一、Git仓库介绍 开发者可以通过Git仓库来存储和管理文件代码&#xff0c;Git仓库分为两种&#xff1a; 本地仓库&#xff1a;开发人员自己电脑上的Git仓库 远程仓库&#xff1a;远程服务器上的Git仓库 仓库之间的运转如下图&#xff1a; commit&#xff1a;提交&#xff…

Decoupled Knowledge Distillation解耦知识蒸馏

Decoupled Knowledge Distillation解耦知识蒸馏 现有的蒸馏方法主要是基于从中间层提取深层特征&#xff0c;而忽略了Logit蒸馏的重要性。为了给logit蒸馏研究提供一个新的视角&#xff0c;我们将经典的KD损失重新表述为两部分&#xff0c;即目标类知识蒸馏&#xff08;TCKD&a…

c++之旅——第四弹

大家好啊&#xff0c;这里是c之旅第三弹&#xff0c;跟随我的步伐来开始这一篇的学习吧&#xff01; 如果有知识性错误&#xff0c;欢迎各位指正&#xff01;&#xff01;一起加油&#xff01;&#xff01; 创作不易&#xff0c;希望大家多多支持哦&#xff01; 本篇文章的主…

如何对比 MySQL 主备数据的一致性?

随着业务范围的扩大&#xff0c;很多企业为了保障核心业务的高可用性&#xff0c;选择了 MySQL 主从架构&#xff0c;这一套方案通常具备主备数据同步、数据备份与恢复、读写分离、高可用切换等特性&#xff0c;是一种相当成熟可靠的数据库架构方案。然而这套方案在特定情况下可…

Redis小白入门教程

Redis入门教程 1. Redis入门1.1 Redis简介1.2 Redis服务启动与停止1.2.1 Redis下载1.2.2 服务启动命令1.2.3 客户端连接命令1.2.4 修改Redis配置文件 2. Redis数据类型2.1 五种常用数据类型介绍2.1.1 字符串操作命令2.1.2 哈希操作命令2.1.3 列表操作命令2.1.4 集合操作命令2.1…

双周回顾#006 - 这三个月

断更啦~~ 上次更新时间 2023/11/23, 断更近三个月的时间。 先狡辩下&#xff0c;因为忙、着实忙。因为忙&#xff0c;心安理得给断更找了个借口&#xff0c;批评下自己~~ 这三个月在做啥&#xff1f;跨部门援助&#xff0c;支援公司互联网的 ToC 项目&#xff0c;一言难尽。 …

【C语言】InfiniBand 驱动mlx4_ib_init和mlx4_ib_cleanup

一、中文讲解 这两个函数是Linux内核模块中对于Mellanox InfiniBand 驱动程序初始化和清理的函数。 mlx4_ib_init()函数是模块初始化函数&#xff0c;使用__init宏标注&#xff0c;表示该函数只在模块加载时运行一次。 函数执行的步骤如下&#xff1a; 1. 通过alloc_ordered_w…

数据结构——lesson5栈和队列详解

hellohello~这里是土土数据结构学习笔记&#x1f973;&#x1f973; &#x1f4a5;个人主页&#xff1a;大耳朵土土垚的博客 &#x1f4a5; 所属专栏&#xff1a;数据结构学习笔记 &#x1f4a5;对于顺序表链表有疑问的都可以在上面数据结构的专栏进行学习哦~感谢大家的观看与…

ElasticSearch开篇

1.ElasticSearch简介 1.1 ElasticSearch&#xff08;简称ES&#xff09; Elasticsearch是用Java开发并且是当前最流行的开源的企业级搜索引擎。能够达到实时搜索&#xff0c;稳定&#xff0c;可靠&#xff0c;快速&#xff0c;安装使用方便。 1.2 ElasticSearch与Lucene的关…

模拟器抓HTTP/S的包时如何绕过单向证书校验(XP框架)

模拟器抓HTTP/S的包时如何绕过单向证书校验&#xff08;XP框架&#xff09; 逍遥模拟器无法激活XP框架来绕过单向的证书校验&#xff0c;如下图&#xff1a; ​​ 解决办法&#xff1a; 安装JustMePlush.apk安装Just Trust Me.apk安装RE管理器.apk安装Xposedinstaller_逍遥64位…

智能边缘小站 CloudPond(低延迟、高带宽和更好的数据隐私保护)

智能边缘小站 CloudPond(低延迟、高带宽和更好的数据隐私保护) 边缘小站的主要功能是管理用户在线下部署的整机柜设施&#xff0c;一个边缘小站关联一个华为云指定的区域和一个用户指定的场地&#xff0c;相关的资源运行状况监控等。 边缘计算 迈入5G和AI时代&#xff0c;新…

利用redis实现秒杀功能

6、秒杀优化 这个是 图灵 的redis实战里面的一个案例 6.1 秒杀优化-异步秒杀思路 我们来回顾一下下单流程 当用户发起请求&#xff0c;此时会请求nginx&#xff0c;nginx会访问到tomcat&#xff0c;而tomcat中的程序&#xff0c;会进行串行操作&#xff0c;分成如下几个步骤…

基于单片机的红外遥控解码程序设计与实现

摘要:该文介绍基于士兰半导体芯片(SC6122)的红外发射遥控器,通过单片机解码程序,实现红外遥控信号的解码和接收。红外接收头与单片机特定的引脚连接,通过设置单片机定时计数器,采样来自红外接收头的高、低电平宽度解码遥控信号。该解码程序设计主要应用在LED数码显示控制…

电机的极数和槽数,机械角度和电角度,霍尔IC,内外转子

什么是电机的极数和槽数&#xff1f; 【第7集】② 正弦波驱动的转矩脉动、正弦电流的时序和相位变化、超前角控制&#xff08;超前角调整&#xff09;、正弦波驱动的各种波形 - 电源设计电子电路基础电源技术信息网站_罗姆电源设计R课堂 (rohm.com.cn) 下面为您介绍表示电机…

Java虚拟机(JVM)从入门到实战【上】

Java虚拟机&#xff08;JVM&#xff09;从入门到实战【上】&#xff0c;涵盖类加载&#xff0c;双亲委派机制&#xff0c;垃圾回收器及算法等知识点&#xff0c;全系列6万字。 一、基础篇 P1 Java虚拟机导学课程 P2 初识JVM 什么是JVM Java Virtual Machine 是Java虚拟机。…

3.2日-线性模型,基础优化方法,线性回归从零开始实现

3.2日-线性模型&#xff0c;基础优化方法&#xff0c;线性回归从零开始实现 1线性模型衡量预估质量训练数据总结2基础优化方法3 线性回归从零开始实现 1线性模型 衡量预估质量 训练数据 总结 2基础优化方法 梯度下降是一种优化算法&#xff0c;常用于机器学习和深度学习中&…

进程的信号

目录 信号(signal)入门 技术应用角度的信号 注意 用kill -l命令可以察看系统定义的信号列表 信号处理常见方式概览 产生信号 1.通过终端(键盘)按键产生信号 signal函数 2. 调用系统函数向进程发信号 kill 函数 raise 函数 3.由软件条件产生的信号 alarm 函数 4.硬…