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,一经查实,立即删除!

相关文章

GROM gorm.DB 对象剖析

文章目录 1.GORM 简介2.gorm.DB 简介2.1 定义2.2 初始化2.3 查询方法2.4 事务支持2.5 模型关联2.6 钩子&#xff08;Hooks&#xff09;2.7 自定义数据类型 3.为什么不同请求可以共用一个 gorm.DB 对象&#xff1f;4.链式调用与方法5.小结参考文献 1.GORM 简介 GORM 是一个流行…

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

社区工作者&#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.孤儿…

Redis:缓存问题及解决——缓存穿透、缓存击穿、缓存雪崩

缓存穿透 问题描述 当系统中引入redis缓存后&#xff0c;一个请求进来后&#xff0c;会先从redis缓存中查询&#xff0c;缓存有就直接返回&#xff0c;缓存中没有就去db中查询&#xff0c;db中如果有就会将其丢到缓存中&#xff0c;但是有些key对应数据在db中并不存在&#x…

管理员配置Jupterhub

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

后端防止重复提交相同数据处理方式(Redis)

使用AOP注解处理接口幂等性&#xff0c;默认禁止同一用户在上次提交未果后10秒内又重复提交 在原先的sameUrlData的注解上进行了copy新建优化&#xff0c;使用redis去setnx的参数视项目使用点而调整&#xff0c;不一定是每个项目都适合这种取参形式。 源码如下: package com…

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;没有…

Configure ssh-config简化ssh , scp命令;Screen 后台运行命令

1. Configure .ssh/config简化ssh, scp命令 # Configure myServer Host myServerHostName <ServerIP>User ubuntuIdentityFile /home/ubuntu/.ssh/<myServerKey>.pemssh 命令简化为. ssh myServer ssh myServerscp 命令简化为 scp -rp test.txt myServer:~/Down…

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;这里…

C/C++---------------LeetCode第27. 移除元素

移除元素 题目及要求双指针在main内使用 题目及要求 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元…

MySQL数据库SQLSTATE[22007]: Invalid datetime format 日期类型不能为空值的解决办法

如果你的数据库是mysql&#xff0c; 如果你创建表或插入数据时遇到的BUG–它长这样&#xff1a; Invalid datetime format: 1292 Incorrect datetime value: ‘’ for column ‘xxx’ at row 1 或 1067 - Invalid default value for ‘xx’ 那么我将赐予你 两套剑法: &#…

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

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

MySQL远程连接数据库

【0】数据库的安装及配置 Windows安装MySQL - 知乎 (zhihu.com) 【1】mysql远程连接数据库 1. 首先打开打开cmd窗口&#xff1a;winr ---------- cmd 2.输入用户名和密码进入数据库&#xff1a;mysql -u root -p 3.打开use mysql表&#xff1a;use mysql 4.执行远程连接(授…

TCP/IP_整理起因

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