C语言之指针详解(4)

文章目录

  • 一、回调函数
  • 二、qsort使用举例
    • 2.1使用qsort函数排序整型数据
    • 2.2使用qsort函数排序结构体数据
  • 三、qsort函数的模拟实现

一、回调函数

首先我们先来了解一下什么是回调函数

回调函数通俗来讲就是一个通过函数指针调用的函数。

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

先来看看下面的代码,想一想有没有可以用回调函数的方法来进行改进的地方。

//使用回调函数改造前
#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;
}
int main()
{int x, y;int input = 1;int ret = 0;do{printf("*************************\n");printf(" 1:add             2:sub \n");printf(" 3:mul             4:div \n");printf("*******   0.exit   ******\n");printf("*************************\n");printf("请选择:");scanf("%d", &input);switch (input){case 1:printf("输入操作数:");scanf("%d %d", &x,&y);ret = add(x, y);printf("ret = %d\n",ret);break;case 2:printf("输入操作数:");scanf("%d %d", &x,&y);ret = sub(x, y);printf("ret = %d\n",ret);break;case 3:printf("输入操作数:");scanf("%d %d", &x,&y);ret = mul(x, y);printf("ret = %d\n",ret);break;case 4:printf("输入操作数:");scanf("%d %d", &x,&y);ret = div(x, y);printf("ret = %d\n",ret);break;case 0:printf("退出程序\n");break;default:printf("选择错误\n");break;}} while (input);return 0;
}

可以看到,在这段代码里面,输入操作数,函数调用,打印结果这些地方总是在重复的进行,因此我们可以把调用的函数的地址以参数的形式传递过去,使用函数指针接收,函数指针指向什么函数就调用什么函数,这里其实使用的就是回调函数的功能。

修改代码如下:

//使用回调函数改造后
#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 x, y;int input = 1;int ret = 0;do{printf("*************************\n");printf(" 1:add             2:sub \n");printf(" 3:mul             4:div \n");printf("*******   0.exit   ******\n");printf("*************************\n");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;
}

二、qsort使用举例

qsort函数是一个用来排序的函数,默认情况下是由小到大排序。并且qsort函数可以排序任意类型的数据比如:整型,浮点型,结构体等等都可以。

使用这个函数需要传入四个参数:

  • 需要排序的数组的第一个元素的指针
  • 数组的长度
  • 每个元素的字节大小
  • 比较两个元素的函数的指针

下面是两个用qsort函数进行排序的例子。

2.1使用qsort函数排序整型数据

#include <stdio.h>
//qosrt函数的使用者得实现一个比较函数
int int_cmp(const void* p1, const void* p2)
{return (*(int*)p1 - *(int*)p2);
}
int main()
{int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };int i = 0;qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(int), int_cmp);for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){printf("%d ", arr[i]);}printf("\n");return 0;
}

2.2使用qsort函数排序结构体数据

#include <string.h>
#include <stdlib.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;
}
//strcmp - 是库函数,是专⻔用来⽐较两个字符串的大小的
//假设按照名字来比较
int cmp_stu_by_name(const void* e1, const void* e2)
{return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}
//按照年龄来排序
void test2()
{struct Stu s[] = { {"zhangsan", 20}, {"lisi", 30}, {"wangwu", 15} };int sz = sizeof(s) / sizeof(s[0]);qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);
}
//按照名字来排序
void test3()
{struct Stu s[] = { {"zhangsan", 20}, {"lisi", 30}, {"wangwu", 15} };int sz = sizeof(s) / sizeof(s[0]);qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);
}
int main()
{test2();test3();return 0;
}

三、qsort函数的模拟实现

使用回调函数,模拟实现qsort函数(采用冒泡排序的方式,原来的qsort函数采用的是快速排序的方式)

我们要从观察原有的函数开始来进行模拟实现

首先,原来的函数的声明是这样的:

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

说明:

  • 函数没有返回值(那是肯定的呀,因为我们只需要这个函数能够将我们需要的内容排好序就行了)。
  • 函数的第一个参数是一个没有类型的指针,用来指向需要排序的数组的第一个元素(因为不知道使用这个函数的人需要排元素类型是是什么的数组)。
  • 第二个参数是一个无符号整数类型(因为个数肯定是正的,所以用无符号整数类型),是指数组的元素个数。
  • 第三个参数也是一个无符号整数类型(元素的字节大小肯定也是正整数),是指数组中每个元素的字节大小(当我们知道字节大小后就可以知道这个元素所占的空间大小了。这样我们在函数实现时,元素的交换,就可以知道交换多大的字节空间了)。
  • 第四个参数是一个函数的指针,这个指向的函数是用来比较数组元素之间的大小的。

代码如下:

#include <stdio.h>
int int_cmp(const void* p1, const void* p2)
{return (*(int*)p1 - *(int*)p2);
}
void _swap(void* p1, void* p2, int size)
{int i = 0;for (i = 0; i < size; i++){char tmp = *((char*)p1 + i);*((char*)p1 + i) = *((char*)p2 + i);*((char*)p2 + i) = tmp;}
}
void bubble(void* base, int count, int size, int(*cmp)(void*, void*))
{int i = 0;int j = 0;for (i = 0; i < count - 1; i++){for (j = 0; j < count - i - 1; j++){if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0){_swap((char*)base + j * size, (char*)base + (j + 1) * size,size);}}}
}
int main()
{int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };int i = 0;bubble(arr, sizeof(arr) / sizeof(arr[0]), sizeof(int), int_cmp);for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){printf("%d ", arr[i]);}printf("\n");return 0;
}

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

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

相关文章

【微服务】本地事务和远程调用的执行先后关系以及带来的风险和解决方案

前言 在做订单模块的时候&#xff0c;本地事务中包含了远程调用&#xff0c;引发一些问题&#xff0c;这里做一次简单的复盘。 1、问题复现 首先下完订单&#xff0c;调用支付服务成功&#xff0c;然后支付服务收到微信的回调&#xff0c;然后通知我支付结果 但是我的支付回…

canvas层级太高?解决方法

这个方法主要是依赖于邀请好有页面展示的canvas二维码二维码以及其他容器的图片 有一个保存图片功能&#xff0c;这个保存图片是需要将二维码以及涉及到的其他容器比如下图&#xff1a; 所以这时候需要canvas来绘制一个保存图片的效果&#xff0c;然后对这个canvas绘制的图片保…

web网络安全知多少

web安全性包括: 客户端脚本安全和服务器端应用服务器 客户端脚本安全: ● 跨站脚本攻击(XSS ) ● 跨站点请求伪造(CSRF) ● 点击劫持(ClickJacking) ● HTML 5 安全性 服务端应用安全: ● 注入攻击 ● 文件上传漏洞 ● 认证与会话管理 ● 访问控制 ● DDos攻击 个人意识和个人…

【CALayer-时钟练习-界面-锚点 Objective-C语言】

一、接下来,我们来说这个时钟练习 1.这个里边呢,有这么一个表盘的一个效果,然后呢,这个秒针,跟我们的时间,是同步的, 新建一个项目, Name:05-时钟练习 然后呢,给这个控制器的View,一个背景颜色,先, 背景颜色, 2.接下来,我们开始来做,我们现在这个表盘啊,是我们…

关于前端项目依赖的node版本冲突的问题

最近在几个不同的项目切换 有老的项目有新的项目 当中所需要的node版本冲突 苦思半天后好像有个简单的办法来进行解决node 冲突的问题 1&#xff1a;更改项目配置文件 在package.json中增加对应的node版本 当前项目就不会出现版本过高的语法无法使用的问题 视乎是一个比较方…

绿色瓶装水“暗战”竞争越发激烈,华润饮料谋上市同时多地扩产能

《港湾商业观察》黄懿 4月23日&#xff0c;纯净水牌“怡宝”母公司华润饮料&#xff08;控股&#xff09;有限公司&#xff08;下称“华润饮料”&#xff09;向港交所主板提交上市申请&#xff0c;联席保荐人为中银国际、中信证券、美银美林、瑞银集团。 在华润饮料递表不久之…

【ARM+Codesys案例】基于全志T3+Codesys软PLC的3C点胶边缘控制解决方案:整合了运动控制、视觉、激光测高等技术

视觉精密点胶控制方案 针对直交型机构的平面点涂胶应用&#xff0c;基于CODESYS软件平台开发的一站式PC型控制器解决方案&#xff0c;包含运动控制器硬件和点胶应用软件。方案整合了运动控制、视觉、激光测高等技术&#xff0c;高效精密的控制胶水点涂于产品表面或内部&#x…

聊一聊开发语言的基础控制结构

一、描述下for循环、while循环和do-while循环的区别和用法。 在编程中&#xff0c;for循环、while循环和do-while循环是用于重复执行一段代码直到满足特定条件的控制结构。每种循环都有其特定的用途和语法。以下是它们之间的区别和用法&#xff1a; 1. for循环 用法&#xf…

Mac上安装harbor

在Mac Book VMware Fusion 虚拟出来的 ubuntu&#xff08;22.04.4&#xff09;的环境中安装官方离线版本 harbor-offline-installer-v2.10.2.tgz会出现如下错误&#xff1a; prepare base dir is set to /home/zhangzk/harbor WARNING: The requested images platform (linux/…

CHIMA专访美创高级总监丁斐:为医疗数据安全构筑体系化防御新机制

5月17-19日&#xff0c;中国医院信息网络大会&#xff08;CHIMA 2024&#xff09;在南京隆重召开。作为结识多年的老友&#xff0c;美创科技再携以数据为中心的全系列安全业务、新一代数字化安全平台、医疗行业解决方案精彩亮相。 会议期间&#xff0c;CHIMA专访美创科技&…

[数据集][目标检测]RSNA肺炎检测数据集VOC+YOLO格式6012张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;6012 标注数量(xml文件个数)&#xff1a;6012 标注数量(txt文件个数)&#xff1a;6012 标注…

聊天室概述,什么是聊天室呢?

聊天室&#xff08;Chatroom&#xff09;提供了支持高并发消息处理的业务形态&#xff0c;可用于直播、社区、游戏、广场交友、兴趣讨论等场景。App Key 下可创建的聊天室数量没有限制&#xff0c;单个聊天室成员数量没有限制。 服务配置 聊天室不需要申请开通。聊天室的部分…

【基础算法总结】前缀和二

前缀和二 1.和为 K 的子数组2.和可被 K 整除的子数组3.连续数组4. 矩阵区域和 点赞&#x1f44d;&#x1f44d;收藏&#x1f31f;&#x1f31f;关注&#x1f496;&#x1f496; 你的支持是对我最大的鼓励&#xff0c;我们一起努力吧!&#x1f603;&#x1f603; 1.和为 K 的子数…

Java语言ADR药物不良反应系统源码Java+IntelliJ+IDEA+MySQL一款先进的药物警戒系统

Java语言ADR药物不良反应系统源码JavaIntelliJIDEAMySQL一款先进的药物警戒系统源码 ADR药物不良反应监测系统是一个综合性的监测平台&#xff0c;旨在收集、报告、分析和评价药品在使用过程中可能出现的不良反应&#xff0c;以确保药品的安全性和有效性。 以下是对该系统的详细…

Modbus工业网关

随着工业自动化程度的不断提高&#xff0c;设备之间的数据通信与交互变得至关重要。在这一背景下&#xff0c;Modbus协议凭借其简单、可靠、开放的特点&#xff0c;成为了工业自动化领域中最常用的通信协议之一。而HiWoo Box网关作为一款支持Modbus协议的工业网关设备&#xff…

tomcat启动流程

在Tomcat中,每个组件都扮演着不同的角色,共同协作以提供Web服务。以下是对Tomcat中主要组件及其作用的详细解释: Server 作用:Server是Tomcat的顶级组件,代表Tomcat的运行实例。 特点:一个Tomcat服务器只有一个Server组件,它包含Global Naming Resources组件以集成JND…

【全开源】防伪溯源一体化管理系统源码(FastAdmin+ThinkPHP和Uniapp)

一款基于FastAdminThinkPHP和Uniapp进行开发的多平台&#xff08;微信小程序、H5网页&#xff09;溯源、防伪、管理一体化独立系统&#xff0c;拥有强大的防伪码和溯源码双码生成功能&#xff08;内置多种生成规则&#xff09;、批量大量导出防伪和溯源码码数据、支持代理商管理…

Springboot项目——博客平台

前言&#xff1a;为巩固之前学习的知识&#xff0c;同时锻炼自己的代码能力&#xff0c;项目经验&#xff0c;熟悉前后端交互方式等&#xff0c;特此完成一个博客平台系统。&#xff08;总之&#xff0c;为了学习&#xff0c;为了进步&#xff09; 博客平台&#xff1a;本项目…

网络安全的重要组成部分:数据库审计

数据库审计&#xff08;简称DBAudit&#xff09;以安全事件为中心&#xff0c;以全面审计和精确审计为基础&#xff0c;实时记录网络上的数据库活动&#xff0c;对数据库操作进行细粒度审计的合规性管理&#xff0c;对数据库遭受到的风险行为进行实时告警。它通过对用户访问数据…

git 小技巧 old mode new mode问题

在git 提交的时候会遇到 ole mode new mode问题 这个提示说明修改了文件的权限&#xff0c;但是实际上并没有修改&#xff0c;只是修改了文件的内容&#xff0c;应该是编辑器在修改代码的时候的改动了文件的权限 解决办法&#xff1a; 在提交的根目录执行如下命令&#xff1…