c语言-浅谈指针(4)

文章目录

    • 1.回调函数
      • 概念
      • 举例
    • 2.qsort函数
      • qsort的使用
    • 3.通过冒泡排序来模拟qsort函数
      • 排序int类型
      • 排序结构体类型


这是指针最后一篇了喔,完结撒花 !
前三篇:
浅谈指针(1)http://t.csdnimg.cn/JTRjW
浅谈指针(2)http://t.csdnimg.cn/1aPkr
浅谈指针(3)http://t.csdnimg.cn/TndpD

1.回调函数

概念

回调函数就是⼀个通过函数指针调⽤的函数。
如果你把函数的指针(地址)作为参数传递给另⼀个函数,当这个指针被⽤来调⽤其所指向的函数时,被调⽤的函数就是回调函数。回调函数不是由该函数的实现⽅直接调⽤,⽽是在特定的事件或条件发⽣时由另外的⼀⽅调⽤的,⽤于对该事件或条件进⾏响应。通过回调函数能够是代码简便。

如:
实现加法

int add(int x, int y) {return x + y;
}
void   su(int (*p)(int, int)) {int a=10, b=20;printf("%d", p(a, b));
}int main() {su(add);return 0;
}

注:要通过函数指针来接收函数地址

举例

通过回调函数实现计算器
1.选择界面
2.实现加、减。乘、除函数
3.一个接收这四个函数地址的函数
实现:

#include <stdio.h>
int add(int a, int b)//加
{return a + b;
}
int sub(int a, int b)//减
{return a - b;
}
int mul(int a, int b)//乘
{return a * b;
}
int div(int a, int b)//除
{return a / b;
}
void calc(int(*pf)(int, int))//接收函数地址的函数
{int ret = 0;int x, y;printf("输⼊操作数:");scanf("%d %d", &x, &y);ret = pf(x, y);//调用printf("ret = %d\n", ret);
}
int main()
{int input = 1;do{printf("******************printf(" 1:add printf(" 3:mul printf("******************printf("请选择:");scanf("%d", &input);switch (input){case 1:calc(add);//传函数地址break;case 2:calc(sub);break;case 3:calc(mul);break;case 4:calc(div);break;case 0:printf("退出程序\n");break;default:printf("选择错误\n");break;}} while (input);return 0}

虽然说现在看起来还是那么多,那是因为这里只是四个函数而已,如果加上其他的计算功能呢。这样就能够大大减少代码量了

2.qsort函数

对所指向的数组元素进行排序,每个元素的长度为字节,使用函数确定顺序。
此函数使用的排序算法通过调用指定的函数来比较元素对,并将指向元素的指针作为参数。
该函数不返回任何值,而是通过对数组的元素进行重新排序来修改所指向的数组的内容.

在这里插入图片描述
注意的是 compar函数的创建的格式和 qsort的一样: int (*compar)(const void*,const void*));//这个是自己创建的
在这里插入图片描述

qsort的使用

void qsort (void* base, size_t num, size_t size,   int (*compar)(const void*,const void*));

我们来实现一个整形排序

int hanshu(const void* p1,const void* p2) {//这里要按照qsort中的函数参数类型来写 
//int (*compar)(const void*,const void*));return  (*((int*)p1) - *((int*)p2));//返回-上面有解释  (int*)p1--强制转换为int类型指针
}
int main() {int arr[] = { 5,3,2,4,1 };int zs = sizeof(arr) / sizeof(arr[0]);//数组大小qsort(arr, zs, sizeof(arr[0]), hanshu);//按照规则填入, sizeof(arr[0])一个元素占多少字节for (int i = 0; i < zs; i++)//打印printf("%d ", arr[i]);return 0;
}

我们来看看运行结果:
在这里插入图片描述
成功完成排序
那么我们再来试一下结构体

struct sl {//构建结构体char arr[20];int a;
};
int hanshu(void* p1, void* p2) {return  strcmp(((struct sl*)p1)->arr,((struct sl*)p2)->arr);//判断结构体中arr的大小,//strcmp--用于比较两个字符大小   (struct sl*)p1>>强制类型转换成结构体类型指针
}int main() {struct sl s[] = { {"zhangsan",18} ,{"lisi",19}, {"wanwu",12}};int zs = sizeof(s) / sizeof(s[0]);//计算大小qsort(s, zs, sizeof(s[0]), hanshu);//进行排序for (int i = 0; i < zs; i++)//打印printf("%s  %d\n", s[i].arr,s[i].a);//打印结构体return 0;
}

运行结果:
![在这里插入图片描述](https://img-blog.csdnimg.cn/7ca32c0532c84b19a017828d447fe73a.png

总结:qsort函数能够实现多种数据的排序

3.通过冒泡排序来模拟qsort函数

接下来我们通过冒泡排序来模拟qsort函数
不懂冒泡排序的可以看看这个哦:冒泡排序:http://t.csdnimg.cn/0uNZH

1.一般的冒泡排序只能用来排序整数类型,我们想要通过冒泡排序的方式来模拟qsort函数那么我们创造的冒泡函数的参数类型我们也和qsort和参数类型一样。

c void maopao (void* base, size_t num, size_t size, int (*compar)(const void*,const void*));

2.我们比大小时要改变传递给比大小函数的参数,因为我们不知道从主函数传过来的是什么类型数据(如有:char、short、int等类型)。那么怎么改变呢?我们可以将从主函数传过来的数据进行强制类型转换,转为char*
类型(由于char类型的为1字节满足最小的数据类型),转化为char *
后,再通过从主函数传过来的的类型宽度和在循环中的变量来改变指针指向的位置,这样就可以控制传递给比大小函数的指针了。
3.交换时传递的参数和如何交换,跟比大小函数一样,不知道从主函数传过来的数据类型是什么,那么怎么样设置参数和交换呢?我们可以通过一个字节一个字节来交换数据(我们可以通过传递从主函数传过来的数据类型宽度来控制循环次数),那样不管是什么类型都可以交换了,那么我们还是将从主函数传过来的强制类型转换为char

  • 再传过去给交换函数,进行交换。

排序int类型

代码实现:

int  cmp(const void* p1,  const void* p2) {//比大小,因为返回类型为 int ,所以强行转为(int*),再解引用return (*(int*)p1 - *(int*)p2);
}void  huan(char* p1,char* p2, int ws) {//交换函数,ws为类型长度,一个字节一个字节换int i = 0;for (i = 0; i < ws; i++) {//循环的次数和我们比较类型的宽度有关char te = *(p1 + i);*(p1+i) = *(p2+i);*(p2+i) = te;}
}
void  maopao(void* p, int zs, int ws, int (*cmp)(const void*,const  void*)) {//冒泡模拟的qsort函数,传入参数和qsort函数一样int i = 0;for (i = 0; i < zs - 1; i++) {//正常冒泡排序的流程,走n-1趟int j = 0;for (j = 0; j < zs - 1 - i; j++) {//前后对比if (cmp((char*)p + ws * j, (char*)p + ws * (j + 1)) > 0) {//传给cmp函数的参数先转为(char*)类型,再通过变量j和宽度ws就可以找到正确的指针phuan((char*)p + ws * j, (char*)p + ws * (j + 1), ws);//交换//参数先转为(char*)类型,再通过变量j和宽度ws就可以找到正确的指针p}}}}
void dayin1(int arr[], int zs) {//打印for (int i = 0; i < zs; i++)printf("%d ", arr[i]);printf("\n");
}int main() {int arr[10] = { 2,3,6,7,1,4,9,5,0,8 };int zs = sizeof(arr) / sizeof(arr[0]);//求数组元素个数dayin1(arr, zs);//打印原来的数组maopao(arr, zs, sizeof(arr[0]), cmp);//sizeof(arr[0])元素宽度dayin1(arr, zs);printf("\n");return 0;
}

运行结果:
在这里插入图片描述
成功进行排序了
交换过程图解:
在这里插入图片描述

排序结构体类型

代码实现:

struct sl {//创建结构体char r[20];//名字int b;//年龄
};
int  cmp(const void* p1, const void* p2) {return strcmp(((struct sl*)p1)->r, ((struct sl*)p2)->r);//对结构体中的名字比大小
}//strcmp函数  用于字符串比大小void  huan(char* p1, char* p2, int ws) {//交换函数,ws为类型长度,一个字节一个字节换int i = 0;for (i = 0; i < ws; i++) {//循环的次数和我们比较类型的宽度有关char te = *(p1 + i);*(p1 + i) = *(p2 + i);*(p2 + i) = te;}
}
void  maopao(void* p, int zs, int ws, int (*cmp)(const void*, const  void*)) {//冒泡模拟的qsort函数,传入参数和qsort函数一样int i = 0;for (i = 0; i < zs - 1; i++) {//正常冒泡排序的流程,走n-1趟int j = 0;for (j = 0; j < zs - 1 - i; j++) {//前后对比if (cmp((char*)p + ws * j, (char*)p + ws * (j + 1)) > 0) {//传给cmp函数的参数先转为(char*)类型,再通过变量j和宽度ws就可以找到正确的指针phuan((char*)p + ws * j, (char*)p + ws * (j + 1), ws);//交换//参数先转为(char*)类型,再通过变量j和宽度ws就可以找到正确的指针p}}}
}
void dayin2(struct sl s[], int zs) {for (int i = 0; i < zs; i++)printf("%s  %d\n", s[i].r, s[i].b);//打印结构体中的数据printf("\n");
}
int main() {struct sl s[] = {{"zhangsan",18},{"lisi",12},{"wangwu",87}};int zs = sizeof(s) / sizeof(s[0]);//求数组元素个数dayin2(s, zs);//打印原来的数组maopao(s, zs, sizeof(s[0]), cmp);//sizeof(arr[0])元素宽度dayin2(s, zs);printf("\n");return 0;
}

运行结果:
在这里插入图片描述
当然冒泡模拟的qsort还可以进行其他数据类型的排序

以上就是我的分享了,如果有什么错误,欢迎在评论区留言。
最后,谢谢大家的观看!

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

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

相关文章

社区工作者在哪里啊?真救命了

社区工作者&#xff0c;每天各种写材料啊啊啊&#xff01;&#xff01; 有时候真的写麻掉了啊&#xff0c;家人们&#xff0c;太难了&#xff0c;谁懂啊&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 这个好东西真的救我大命啊&#xff0c;只要输入关键词和…

linux基础五:linux 系统(进程状态2:)

linux 系统 一.进程状态&#xff1a;1.睡眠状态(sleep)&#xff1a;2.磁盘休眠状态(disk sleep)&#xff1a;3.停止状态(stoped --- T)&#xff1a;4.死亡状态&#xff1a;5.控制状态&#xff08;t&#xff09; 二.僵尸进程和孤儿进程&#xff1a;1.僵尸状态&#xff1a;2.孤儿…

管理员配置Jupterhub

在Ubuntu上演示如何部署R语言环境&#xff0c;包括 posit的已经编译了一些R的安装 系统已经装了R&#xff0c;我额外编译的R如何让大家都能用到 如何配置RStudio jupyterhub的配置和使用 管理员如何配置jupyterhub 用户如何配置自己的jupyter环境 Ubuntu上的R部署 这一次…

Mendix UI页面布局以案说法

一、前言 试着回想最近一次与公司网站交互的情况&#xff0c;访问了多个页面&#xff0c;并且可能使用了某些功能。有可能基于这种互动&#xff0c;可以向某人介绍公司的一些主要功能。其中一些可能是更肤浅的东西&#xff0c;比如他们的标志是什么样子或他们的主要配色方案是…

笔记二十四、剖析Redux的工作流程

24.1 定义 用做于状态管理的第三方 js 库react框架中使用&#xff0c;也可应用于其他的框架 使用场景 组件间需要共享状态和改变另一个组件的状态在react项目中可以不使用就尽量不用&#xff0c;复杂场景下才使用 24.2 原理图 24.3 代码 安装 yarn add reduxjs/toolkit rea…

GPIO的使用--操作PE02 PE03 PE04实现开关控制灯泡亮灭

效果&#xff1a; 开关控制灯的亮灭 目录 1.找到引脚组别(DEFG) led灯硬件结构 开关硬件结构 2.时钟使能 3.GPIO时钟控制 4.控制实现思路 5. 完整代码 6.视频演示 1.找到引脚组别(DEFG) 开关的引脚组别--E&#xff1b;LED灯的引脚组别--F led灯硬件结构 开关硬件结构…

【linux】基本指令(上篇)

1.快速认识5~6个指令 pwd指令 ls指令 touch指令 cd指令 clear指令 touch指令 详细讲解 首先有一个问题就是当我们创建一个文件&#xff0c;但是没有往里面写内容&#xff0c;那么磁盘上会有该文件吗&#xff1f; 磁盘上会保存&#xff0c;因为创建好的文件&#xff0c;没有…

IDEA安装python插件并配置

目录 一、Mac1. 安装插件2. 新建项目3. 下载第三方库4. 配置镜像源 一、Mac 1. 安装插件 在plugins中搜索python 2. 新建项目 使用本项目独享的虚拟环境&#xff0c;选择解释器 如果需要修改解释器可以进入project structure&#xff0c;在SDKs中点击&#xff0c;选择add py…

clip-path,css裁剪函数

https://www.cnblogs.com/dzyany/p/13985939.html clip-path - CSS&#xff1a;层叠样式表 | MDN 我们看下这个例子 polygon里有四个值分别代表这四个点相对于原图左上方的偏移量。 裁剪个五角星

解决vue3项目打包发布到服务器后访问页面显示空白问题

1.在 vite.config.ts 文件中 加入 base:./ 当你将 base 设置为 / 时&#xff0c;它表示你的应用程序将部署在服务器的根路径上&#xff0c;&#xff08;将 base 设置为 / 表示你的应用程序部署在服务器的根路径上&#xff0c;并且 Vite 会相应地处理资源和路由的路径…

【UE】制作一块布

效果 步骤 1. 新建一个空白模板工程&#xff0c;新建一个Basic关卡 2. 选项模式选择“建模” 3. 创建一个矩形 宽度、深度设为500&#xff0c;宽度细分和深度细分设置为100&#xff0c;然后点击接受 此时在浏览器中编辑器也帮我们创建了一个矩形的静态网格体&#xff0c;这里…

Peter算法小课堂—差分与前缀和

差分 Codeforces802 D2C C代码详解 差分_哔哩哔哩_bilibili 一维差分 差分与前缀和可以说成减法和加法的关系、除法和乘法的关系、积分和微分的关系&#xff08;听不懂吧&#xff09; 给定数组A&#xff0c;S为A的前缀和数组&#xff0c;则A为S的差分数组 差分数组构造 现…

TCP/IP_整理起因

先分享一个初级的问题&#xff1b;有个客户现场&#xff0c;终端设备使用客户网络更新很慢&#xff0c;使用手机热点更新速度符合预期&#xff1b;网络部署情况如下&#xff1a; 前期花费了很大的精力进行问题排查对比&#xff0c;怀疑是客户网络问题&#xff08;其他的客户现…

微信开发者工具真机调试连接状态在正常和未连接之间反复横跳

开启局域网模式能解决这个问题&#xff0c;目前只找到这一个方法

Ubuntu安装HP LaserJet P3010系列打印机驱动

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、安装驱动二、其它设置总结 前言 最近在研究Ubuntu Desktop版&#xff0c;无意间看到了打印机选项&#xff0c;就好奇去试了试。居然配置成功了&#xff0c…

单片机实验(三)

前言 实验一&#xff1a;利用定时器T1的中断控制P1.7引脚输出音频信号&#xff0c;启动蜂鸣器发出一段熟悉的与众不同的具有10个音节的音乐音频。 实验二&#xff1a;使用定时器/计数器来实现一个LCD显示年、月、日、星期 、时、分、秒的电子表&#xff0c;要求时和分可以方便…

负电源电压转换-TP7660H

负电源电压转换-TP7660H 简介引脚说明典型应用电路倍压与反压的应用电路 简介 TP7660H 是一款 DC/DC 电荷泵电压反转器专用集成电路。芯片能将输入范围为 2.5V&#xff5e;11V 的电压转换成相应的-2.5V&#xff5e;-11V 的输出&#xff0c;电压转换精度可达99.9%&#xff0c;电…

女子曝被医生男友下药流产,男子被警方行拘10日,医院停职!

近日&#xff0c;一则关于女子被医生男友暗中下堕胎药导致流产的消息引起了广泛关注。经过一个多月的报案和调查&#xff0c;如今有了新的进展。 11月30日&#xff0c;王女士向华商报大风新闻记者证实&#xff0c;北京中关村某医院涉事医生已被行政拘留&#xff0c;被处以行政拘…

RabbitMQ学习一

RabbitMQ学习 RabbitMQ相关概念Virtual host数据隔离SpringAMQP第一种 基本消息模型第二种 WorkQueues模型第三种 发布订阅模型&#xff08;fanout交换机&#xff09;fanout交换机实例 第四种 Direct交换机direct交换机实例基于注解的方式声明——direct交换机 第五种Topic交换…

Spring Security 6.x 系列(7)—— 源码分析之Builder设计模式

一、Builder设计模式 WebSecurity、HttpSecurity、AuthenticationManagerBuilder 都是框架中的构建者&#xff0c;把他们放到一起看看他们的共同特点&#xff1a; 查看AuthenticationManagerBuilder的继承结构图&#xff1a; 查看HttpSecurity的继承结构图&#xff1a; 查看W…