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

news2024/7/11 9:05:52

  

今天给大家在更新一下指针类型的知识,这里讲到了一个库函数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;
}

代码解析:

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

 

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


文章已到末尾,望喜欢。

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

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

相关文章

Java - 获取汉字大写首字母输出

背景 有个项目需要将一批字符串的拼音首字母输出并大写&#xff0c;写了个工具类。 实现 需要引入外部jar。 <dependency><groupId>com.belerweb</groupId><artifactId>pinyin4j</artifactId><version>2.5.1</version> </dep…

数字人解决方案——阿里EMO音频驱动肖像生成能说话能唱歌的逼真视频

前言 数字可以分为3D数字人和2D数字人。3D数字人以虚幻引擎的MetaHuman为代表&#xff0c;而2D数字人则现有的图像或者视频做为输入&#xff0c;然后生成对口型的数字人&#xff0c;比如有SadTalker和Wav2Lip。 SadTalker&#xff1a;SadTalker是一种2D数字人算法&#xff0c;…

Android 中get请求网络数据 详细举例

请求链接 https://api.bilibili.com/x/web-interface/ranking 1.添加网络权限 依赖等 implementation com.squareup.okhttp3:okhttp:4.9.3 implementation com.google.code.gson:gson:2.8.92.写请求类network package com.example.myapplication;import android.graphics.Bi…

【C语言】Leetcode 876. 链表的中间节点

主页&#xff1a;17_Kevin-CSDN博客 专栏&#xff1a;《Leetcode》 题目 通过题目的要求可以判断出有两种示例要解决&#xff0c;一种是偶数节点的链表&#xff0c;一种是奇数节点的链表&#xff0c;应对这两种情况我们需要使程序对二者都可以兼容。 解决思路 struct ListNode…

【论文精读】I-JEPA

摘要 计算机视觉中&#xff0c;常采用基于不变性和基于生成的方法进行自监督学习。对比学习&#xff08;CL&#xff09;是典型的基于不变性的方法&#xff0c;通过预训练方法优化编码器&#xff0c;使其能生成同一图像的两个或多个视图的相似嵌入&#xff0c;其中图像视图通常由…

Linux安全加固功能

提示:工具下载链接在文章最后 目录 一.加固功能介绍二.配置加固功能1.配置安全加固功能1.1 开放目前设备监听的所有端口1.2 只开放80、443、20、21、22端口1.3 防火墙配置工具1.3.1 开放允许访问的端口1.3.2 删除允许访问的端口1.3.3 添加IP地址允许访问规则1.3.4 添加IP地址禁…

脾胃论笔记

焦虑会导致脾胃受伤 焦虑等不良情绪也会导致脾胃受伤&#xff0c;我们称其为肝气不舒。肝气不舒会导致脾胃系统出问题&#xff0c;这叫肝木横逆克脾土&#xff0c;木克土&#xff0c;脾胃就容易受伤。 这样的情况在现代社会特别多。这跟古人就不一样&#xff0c;古人生活相对…

matplotlib.animation 3d姿态动画

目录 演示效果&#xff1a; 演示代码&#xff1a; 保存为gif 演示效果&#xff1a; 演示代码&#xff1a; import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D from matplotlib.animation import FuncAnimation# 定义人体关键点…

Vue3 五天速成

文章目录 day 11. 创建vue3工程3. 响应式数据4. 计算属性 day 25. watch 监视6. watchEffect7. 标签的ref属性 day 38. 回顾TS中的接口_泛型_自定义类型9. props的使用10. 生命周期11. 自定义Hooks12. 路由 基本切换效果13. 路由 两个注意点14. 路由 路由器的工作模式15. 路由 …

鸿蒙 Stage模型-AbilityStage、Context、Want

前提&#xff1a;基于官网3.1/4.0文档。参考官网文档 基于Android开发体系来进行比较和思考。&#xff08;或有偏颇&#xff0c;自行斟酌&#xff09; 一、 AbilityStage 1.概念 AbilityStage是一个Module级别的组件容器&#xff0c;应用的HAP在首次加载时会创建一个AbilitySt…

步进电机驱动器接法

实物 参数 共阳极&#xff1a; 使能给高电平有效 共阴极&#xff1a; 使能给低电平有效 整体接线 参考内容 B站UP范辉

Google Play上架:2024年五月份政策自查之敏感信息访问权限和 API(适用于上架被拒和因AI扫荡被下架或封号)

本文根据谷歌上架政策协议截止日期归纳而出&#xff0c;提供上架遇到问题的开发者们&#xff0c;感谢支持&#xff0c;如有不足&#xff0c;欢迎补充。 关于敏感信息访问权限和 API的相关政策 政策公布日期政策相关内容相关补充内容政策截止日期 政策公布日期 公布日期&#x…

【QT】窗口的大小标题图标设置

窗口的大小标题图标设置 添加一个新的类 创建完成&#xff0c;根据上一节最后的在总结&#xff0c;做个测试&#xff1a; #include "mybutton.h" #include <QDebug>//打印&#xff0c;标准输出 MyButton::MyButton(QWidget *parent) : QPushButton(parent) { …

INFINI Labs 产品更新 | Easysearch 1.7.1发布

INFINI Labs 产品又更新啦~&#xff0c;包括 Console&#xff0c;Gateway&#xff0c;Agent 1.23.0 和 Easysearch 1.7.1。此次版本重点修复历史遗留 Bug 、网友们提的一些需求等。以下是本次更新的详细说明。 INFINI Console v1.23.0 INFINI Console 是一款非常轻量级的多集…

ATFX汇市:油价回落之际加元币值走弱,USDCAD有望刷新年内新高

ATFX汇市&#xff1a;加元是商品货币&#xff0c;币值受到国际油价和精炼石油出口的显著影响。2022年3月份&#xff0c;国际油价达到130美元的峰值水平&#xff0c;随后开启回落走势&#xff0c;时至今日&#xff0c;最新报价在80美元下方&#xff0c;累计跌幅近40%。疲弱的油价…

根据用户名称实现单点登录

一、参数格式 二、后端实现 Controller层 public class IAccessTokenLoginController extends BaseController {Autowiredprivate ISysUserService sysUserService;Autowiredprivate ISingleTokenServiceImpl tokenService;/*** 登录方法** return 结果*/PostMapping("/l…

小家电压力锅WIFI模块供电AC-DC电源芯片特点与SM6035解析

WIFI模块供电的是一种将AC-DC电源芯片交流电转换为直流电的芯片&#xff0c;通常用于为WIFI模块提供电源。这种芯片具有高效、紧凑和可靠等特点&#xff0c;能够满足各种应用场景的需求。 其中&#xff0c;离线开关电源芯片是一种常见的AC-DCLED电源芯片&#xff0c;它通常包括…

JimuReport积木报表 v1.7.1 版本发布,低代码报表工具

项目介绍 一款免费的数据可视化报表&#xff0c;含报表和大屏设计&#xff0c;像搭建积木一样在线设计报表&#xff01;功能涵盖&#xff0c;数据报表、打印设计、图表报表、大屏设计等&#xff01; Web 版报表设计器&#xff0c;类似于excel操作风格&#xff0c;通过拖拽完成报…

JavaScript基础知识(三)

JavaScript基础知识&#xff08;三&#xff09; 一、事件1. 事件绑定2.事件流2.1 事件捕获与事件冒泡 3.事件对象扩展3.1 阻止事件冒泡3.2 事件默认行为 4.事件委托5.事件类型5.1 鼠标事件5.2 键盘事件5.3 触屏事件 二、计时器方法1. setInterval 与 clearInterval2. setTimeou…