指针中的回调函数与qsort的深度理解与模拟

  

今天给大家在更新一下指针类型的知识,这里讲到了一个库函数sqort,以及回调函数的理解。

望喜欢

目录

回调函数

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("******************");
		printf(" 1:add ");
		printf(" 3:mul ");
		printf("******************");
		printf("请选择:");
		scanf("%d", &input);
		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;
}

 我们是否一眼就看出里面的重复部分(scanf x ,y  和打印结果的过程)比较多,我们是否能想出一个办法来解决这个问题,竟然我们要讲到回调函数了那么我们的解决方法就是我们要说的回调函数了,下面我就来讲讲如何·使用回调函数来实现简便。

注:这里简化的方法不仅可以用回调函数来实现,还可以使用转移表的方法来实现即函数指针数组来完成。


那么我们再来看一下经过使用回调函数的方法来进行化简的代码:

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;
}

那我们仔细对比就会发现哦我们这里多了一个我们不知道的函数,就是calc 函数 那么这便是回调函数,大家可以看到我们在输入想使用的计算方法后,我们都会向回调函数传进去一个相应计算方法的指针,那么这时我们就会再回调函数中通过对应的指针调用这个计算方法的函数。

 讲了那么多那么我们看看我们这里的回调函数的代码是怎么样的: 

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);
}

这里难点在于函数指针即pf,我们这里的形参就是一个函数指针 pf。然后就是根据传进来的函数指针调用计算函数。

这便是回调函数的理解与解析了。


qsort函数

我们看一下cplusplus的解析:

我们现在借助一下图来理解此函数:

 

相信图解已经可以大概理解这个函数了,那么下面我们来用它实现一下冒泡排序的函数:

int cmp_int(void* p1, void* p2)
{
	return *(int*)p1 - *(int*)p2;

}





void print(int* p1,int sum)
{
	for (int i = 0; i < sum; i++)
	{

		printf("%d ", p1[i]);

	}

}





int main()
{
	int arr[10] = { 11,2,3,4,66,34,13,15,16,10 };
	qsort(arr, 10, sizeof(arr[1]), cmp_int);

	print(arr, 10);

	return 0;
}

们先定义一个cmp_int函数然后按照上图进行传参就可以正常运行了。

大家通过运行结果截图 就可以看到,代码就已经可以完美的运行成功了,完成了排序了。这里我


qsort模拟实现

那么为了更好的理解qsort函数那么接下来我们来模拟实现一下qsort函数:

int cmp_int(void* p1, void* p2)
{
	return *(int*)p1 - *(int*)p2;

}

void print(int* p1,int sum)
{
	for (int i = 0; i < sum; i++)
	{

		printf("%d ", p1[i]);

	}

}


void swap(char* p1, char* p2, size_t with)
{
	for (int i = 0; i < with; i++)
	{
		char tem = *p1;
		*p1 = *p2;
		*p2 = tem;
		p1++;
		p2++;
	}


}







void Subble_sort(void* base, size_t sz, size_t with, int (*cmp)(void* p1, void* p2))
{
	int i, j;
	for (i = 0; i < sz - 1; i++)
	{
		for (j = 0; j < sz - 1 - i; j++)
		{
			if (cmp((char*)base + j * with, (char*)base + (j + 1) * with) > 0)
			{
				swap((char*)base + j * with, (char*)base + (j + 1) * with, with);

			}
		}
	}

}

int main()
{
	int arr[10] = { 11,2,3,4,66,34,13,15,16,10 };
	Subble_sort(arr, 10, sizeof(arr[1]), cmp_int);

	print(arr, 10);

	return 0;
}

代码解析:

这里我们模拟实现的代码中我们仔细一想其实冒泡的趟数是不变的 ,所以冒泡的趟数代码我们就不修改这里的代码了,那么我们要改动的就是比较函数,因为在传进来的数据中不一定是都是整形数组,也可能是字符串数组或结构体数组,我们都需要对此进行改变一下比较函数。这里的交换函数其实我们不需要 不断根据数组类型而改变,因为我们这里是一个一个字节的对两个元素进行交换,只要我们知道元素类型的大小那么我们就可以进行交换任何类型的数组元素。

 

这里函数用整形数据是成功运行的,其他类型的数组就不进行尝试了,在这之前我也尝试过了。


文章已到末尾,望喜欢。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

利用文件实现进程间共享数据

概述 文件可以存储任何非结构化字节序列&#xff0c;这个比较简单&#xff0c;就一个写一个读&#xff1b;学习到此&#xff0c;留个记录&#xff0c;以后可以直接抄代码&#xff0c;哈哈 Demo代码 #include <fstream> #include <iostream> #include <thread&…

CMIP6数据处理方法与典型案例分析

气候变化对农业、生态系统、社会经济以及人类的生存与发展具有深远影响&#xff0c;是当前全球关注的核心议题之一。IPCC&#xff08;Intergovernmental Panel on Climate Change&#xff0c;政府间气候变化专门委员会&#xff09;的第六次评估报告明确&#xff1b;指出&#x…

职场卷王:我用可视化大屏模板做工作汇报,惊艳了同事和领导。

2023结束了&#xff0c;我和我的小伙伴们纷纷开始忙碌的年终总结和汇报。 正忙着汇总Excel数据、写word讲稿、找PPT模板时&#xff0c;我发现隔壁组的老王独自在大会议室偷偷调试起了那台汇报用的电视机。 不会吧不会吧&#xff0c;年终汇报还有一周呢&#xff0c;这家伙PPT都…

Java中文件的相关知识及文件IO操作

在我们日常生活中&#xff0c;会把许多东西都称之为文件。比如&#xff0c;一份纸质报告&#xff0c;或u盘中的一些文档&#xff0c;都会把它们称为文件。那么&#xff0c;这里说的文件是以操作系统的角度出发的。在操作系统中&#xff0c;会把许多硬件设备和软件资源都抽象成“…

Kafka | SpringBoot集成Kafka

SpringBoot集成Kafka 一、前言二、项目1. pom2. application.properties4. 消息生产者-测试5. 消息消费者 三、启动测试四、有总结的不对的地方/或者问题 请指正, 我在努力中 一、前言 该文章中主要对SpringBoot 集成Kafka 主要是 application.properties 与 pom坐标就算集成完…

win11系统中nginx简单的代理配置

一.背景 为了公司安排的师带徒任务。 操作系统版本&#xff1a;win11家庭版 nginx版本&#xff1a;1.24.0 二.配置代理 之前文章已经说明了nginx简单的安装&#xff0c;要看阅读这个文章哈。web服务器nginx下载及在win11的安装-CSDN博客 1.配置需求识别 前端服务nginx(80…

【面试题】webpack的五大核心、构建流程、性能优化

【面试题】webpack的五大核心、webpack的构建流程、webpack的性能优化 webpack是什么?webpack的五大核心webpack的构建流程webpack性能优化 webpack是什么? js静态模块打包工具。 功能 将多个文件打包成更小的文件&#xff0c;(压缩)翻译 babal-loader es6进行降级兼容。 …

低代码:数智化助力新农业发展

随着科技的飞速发展和数字化转型的深入推进&#xff0c;低代码开发平台正逐渐成为软件开发的热门话题。尤其在农业领域&#xff0c;低代码技术为传统农业注入了新的活力&#xff0c;助力新农业实现高效、智能的发展。 低代码开发平台的概念与特点 随着科技的飞速发展&#xff0…

猫咪冻干的价格差别为什么那么大?价格实惠的主食冻干分享

随着养猫科学知识的普及&#xff0c;越来越多的铲屎官选择更符合猫咪饮食天性的主食冻干喂养。尽管有些铲屎官因价格犹豫&#xff0c;但像我这样的资深铲屎官深知其益处。尽管其价格稍高于烘焙粮和膨化粮&#xff0c;但主食冻干为猫咪健康带来的实际好处是无法估量的。 对于像我…

代码学习记录11

随想录日记part11 t i m e &#xff1a; time&#xff1a; time&#xff1a; 2024.03.04 主要内容&#xff1a;今天的主要内容是深入了解栈和队列中比较难的题录类型&#xff1a;滑动窗口最大值与前 K K K 个高频元素&#xff0c;最后对于这三天学习的队列和栈的知识进行总结。…

结构体详解

结构体 什么是结构体 结构体是一种用户自定义的数据类型&#xff0c;可以组合多个相关值成为一个单一类型。它是由一批数据组合而成的结构型数据&#xff0c;结构体可以包含多个不同类型的字段&#xff0c;如基本数据类型、其他结构体、枚举类型等。在Rust中&#xff0c;结构…

Ubantu 18.04 配置固定IP

1.首先在终端里输入命令,将你的网关和ip&#xff0c;记下来 ifconfig 2. 执行命令&#xff1a; sudo gedit /etc/network/interfaces 3.在弹出来的框里输入 auto后面的就是网关&#xff0c;address是你虚拟机的ip&#xff0c;gateway是你的网关ip&#xff0c;netmask是你的子…

Python从0到100(二):Python语言介绍及第一个Pyhon程序

前言&#xff1a; 零基础学Python&#xff1a;Python从0到100最新最全教程。 想做这件事情很久了&#xff0c;这次我更新了自己所写过的所有博客&#xff0c;汇集成了Python从0到100&#xff0c;共一百节课&#xff0c;帮助大家一个月时间里从零基础到学习Python基础语法、Pyth…

如何通过抖捧轻松开启AI常态化自动直播间

在如今的互联网时代&#xff0c;短视频和直播已成为大多数企业与实体商家必备的经营技能&#xff0c;不只是全国头部的品牌&#xff0c;他们纷纷加码直播&#xff0c;更有一些已经开启了直播矩阵的体系&#xff0c;包括中小型的商家&#xff0c;他们也在考虑一件事情&#xff0…

前端接收流,并下载到本地

碰到一个大坑&#xff0c;附件文件存在华为云上&#xff0c;查询列表里记录的附件给了一个https开头的url&#xff0c;要求点击附件图标&#xff0c;下载附件到本地&#xff0c; 思路1.直接<a hrefurl downloadfileName >下载</a> 实际效果&#xff1a;跨域下载不…

Java批量修改文件目录名称(树行结构、批量重命名)

Java批量修改文件目录名称(树行结构、批量重命名) 1.读取某个路径的文件目录结构 2.递归批量修改目录文件前缀进行递增 3.结果截图 4.代码 package com.zfi.server.device;import java.io.File; import java.util.Arrays; import java.util.Comparator;public class FileTest…

【ArcPy】游标访问几何数据

访问质心坐标相关数据 结果展示 代码 import arcpy shppath r"C:\Users\admin\Desktop\excelfile\a2.shp" with arcpy.da.SearchCursor(shppath, ["SHAPE","SHAPEXY","SHAPETRUECENTROID","SHAPEX","SHAPEY",&q…

2024抖店全新教程,关于选品和对接达人的流程,细节分享如下

我是王路飞。 对做无货源抖店的商家来说&#xff0c;如何找到一个好的产品&#xff0c;并且把它卖出去&#xff0c;非常重要。 因此&#xff0c;商家的选品能力、达人资源的对接&#xff0c;就很关键了。 今天给你们聊下2024年做抖店&#xff0c;如何选品并且对接到靠谱的带…

MySQL王国:从基础到高级的完整指南【文末送书-28】

文章目录 MySQL从入门到精通第一部分&#xff1a;MySQL基础第二部分&#xff1a;MySQL进阶第三部分&#xff1a;MySQL高级应用 MySQL从入门到精通&#xff08;第3版&#xff09;&#xff08;软件开发视频大讲堂&#xff09;【文末送书-28】 MySQL从入门到精通 MySQL是一种开源…

记录开发过程中遇到的oracle 分页问题

问题: oracle 分页查询,因为是相对来说比较复杂的sql,一直以为是union all 的问题. 结果是相同时间相同,order by 时间之后 、分页查询的每次结果都不能保证与自己直接查询的不分页数据保持一致、导致有些数据看不到 解决方案: order by 条件最后添加一个表中不会重复的字段比如…