一起来攻克回调函数(学习笔记)

news2024/11/26 0:27:09

1:回调函数的简单说明

回调函数概念,和应用场景。其实是比较复杂的,但是我们尝试从易到难。

1:我们先了解回调函数,先看代码

 
  1.    #include<stdio.h>
        int test1(int x,int y)
        {
            printf("x+y=%d\n",(x+y));
            return 0;
        }
        void test2( int (*p)(int ,int ))   //这里使用int(*p)();也是可行的,推荐是用这种,不带参数声明的,
        {
            int y=1;
            int z=2;
            (*p)(y,z);
        }
        int main()
        {
            test2(test1);
            return 0;
        }

至少存在3个函数(回调函数+回调者函数+主函数(不一定要是主函数也可以是任意合法函数)

函数2中必须存在一个形参,这个形参必须是函数指针类型void (*p)(),注意空函数指针也能作为形参。而且空指针称为垃圾桶指针(注意不是垃圾指针),什么类型的指针都能赋值给它

我们在函数1(假设为main主函数)中调用test2,此时该把什么参数传递给test2void (*p)()的形参吗?是不是应该给个函数名(本质是该函数的入口地址),于是我们把tset1作为实参,传递出去。

此时,代码跑到test2函数内部。此时我们使用(*p)(y,z),来调用函数test1。这就实现了,在没有调用test1的情况下,实现了test1的功能。

现在让我们把 情况复杂化,假如test2是封装在头文件,或者库中的函数。这个库或头文件中的函数,必须要调用客户自定义的一个函数test1或者要接收test放回的一个值。这时回调函数的意义和作用就显现出来了。

这时有同学问了,什么我大名鼎鼎,无所不能的库函数还要去调用,用户定义的函数,不可能绝对不可能!!

莫急,我们直接来看,c中的qsort()函数。这是关于对数组,字符串自动进行排序的一个库函数。

2:通过详细的示例解释回调函数

我们先来看看这个函数的原型

viod qsort()表明其函数没有返回值。

第一个参数:void *base 是需要排序的字符或数组的首地址。这里必须声明的一点是,void声明一个指针变量,是C中比较特殊的一种用法。

    printf("我们定义一个viod类型的指针*pvoid:");
    void *pvoid;
    printf("打印此空指针的地址%p\n",&pvoid);
    printf("打印此空指针的大小%d\n",sizeof(pvoid));
    printf("看看此空指针+1后地址移动了几位%d",(pvoid+1)-pvoid);

查看一下输出结果:

可以看到void类型指针,系统是一样的为其开辟了内存空间,大小同其他指针变量一样都是8个字节,可以进行算术运算,和自增自减操作。

空指针还能作为函数形参(也就是被调用函数中的参数),此种情况下,任何指针变量和指针常量都能传入到形参中去。但是在实际使用时,必须强制转换。才能正确使用。

注意,void修饰指针变量是合法操作,但是千万不能用void来修饰普通变量。我们在函数声明或定义时,viod fun_1(void),表明,该函数是没有参数的

看第二个参数:size_t mun,是表明该需要排列数组或字符串的个数。

第三个参数:size_t width ,是表明需要排列数组或字符,每一个元素的Byte数,如int arr1[],这个参数就是4,char arr2[],z这个参数就是1。

最后一个参数:一个函数指针,是学习的重点 int(cdcel_*compare)(const void *element1,const void *element));

这是一个函数指针,作为库函数的形参。那么这个参数就可以被传递各种各样的函数名。

于是接下来,我就自己写了个排序函数,并且利用了回调函数的性质。

/*第一个函数是交换函数*/
void Swap(char*e1,char*e2,int width)
{
	for (int i = 0; i < width; i++)
	{

		char tmp = *e1;
		*e1 = *e2;
		*e2 = tmp;
		e1++;
		e2++;
	}
}

int cmp_my(const void* e1, const void* e2)
{
	return *((int*)e1) - (*(int*)e2);
}


void SelfDefine_sort(void *base,int sz,int width,int (*p)(),void(*p2)())
{
	for (int i = 0; i < sz - 1; i++)
	{
		for (int j = 0; j < sz - (1 +i); j++)
		{
			if (p((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
			{
				p2((char*)base + j * width, (char*)base + (j + 1) * width,width);
			}
		}
	}
}

void print_char(char *arr,int sz)
{
	for (int i = 0; i < sz; i++)
		printf("%c ", arr[i]);
}
void print_int(int *arr,int sz)
{
	for (int i = 0; i < sz; i++)
		printf("%d ", arr[i]);
}

#include<stdio.h>
#include<string.h>
int main()
{
    /*先比较int类型的数组*/
	int arr[] = { 90,889,767,56,51,1114,323,21,100 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	print_int(arr, sz);
	printf("\n");
	SelfDefine_sort(arr, sz, sizeof(arr[0]), cmp_my,Swap);
	print_int(arr, sz);
	/*再比较char类型的字符数组*/
	char Arr_char[] = "WOAIwangjiahang";
	int sz1 = sizeof(Arr_char) / sizeof(Arr_char[0]);
	print_char(Arr_char, sz1);
	printf("\n");
	SelfDefine_sort(Arr_char, sz1, sizeof(Arr_char[0]), cmp_my,Swap);
	print_char(Arr_char, sz1);

	return 0;
}

有了上面的基础,要写出返回类型为函数指针的函数应该不难了,下面这个例子就是返回类型为函数指针的函数:
void (* func5(int, int, float ))(int, int)
{
    ...
}
在这里, func5 以 (int, int, float) 为参数,其返回类型为 void (*)(int, int) 。 

在开始讲解回调函数前,最后介绍一下函数指针数组。既然函数指针也是指针,那我们就可以用数组来存放函数指针。下面我们看一个函数指针数组的例子:

 
  1. /* 方法1 */

  2. void (*func_array_1[5])(int, int, float);

  3. /* 方法2 */

  4. typedef void (*p_func_array)(int, int, float);

  5. p_func_array func_array_2[5];

上面两种方法都可以用来定义函数指针数组,它们定义了一个元素个数为5,类型是 void (*)(int, int, float) 的函数指针数组。

 

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

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

相关文章

微博数据可视化分析:利用Python构建信息图表展示话题热度

1. 引言 随着社交媒体的迅速发展&#xff0c;微博已成为人们交流观点、表达情感的重要平台之一。微博评论数据蕴含着丰富的信息&#xff0c;通过对这些数据进行分析和可视化&#xff0c;我们可以深入了解用户对特定话题的关注程度和情感倾向。本文将介绍如何利用Python进行微博…

mysql数据库表数据创建时间、更新时间自动生成配置

create_time&#xff1a;CURRENT_TIMESTAMP DEFAULT_GENERATED update_time&#xff1a;on update CURRENT_TIMESTAMP

HarmonyOS4.0系统性深入开发34栅格布局(GridRow/GridCol)

栅格布局&#xff08;GridRow/GridCol&#xff09; 概述 栅格布局是一种通用的辅助定位工具&#xff0c;对移动设备的界面设计有较好的借鉴作用。主要优势包括&#xff1a; 提供可循的规律&#xff1a;栅格布局可以为布局提供规律性的结构&#xff0c;解决多尺寸多设备的动态…

【漏洞复现-通达OA】通达OA share存在前台SQL注入漏洞

一、漏洞简介 通达OA&#xff08;Office Anywhere网络智能办公系统&#xff09;是由北京通达信科科技有限公司自主研发的协同办公自动化软件&#xff0c;是与中国企业管理实践相结合形成的综合管理办公平台。通达OA为各行业不同规模的众多用户提供信息化管理能力&#xff0c;包…

基于 SEBAL 模型的河套灌区永济灌域蒸散发估算及其变化特征_李彦彬_2023

基于 SEBAL 模型的河套灌区永济灌域蒸散发估算及其变化特征_李彦彬_2023 摘要关键词 1 数据1.1 研究区概况1.2 数据来源 2 研究方法2.1 SEBAL 模型原理2.2 FAO P-M 公式2.3 模型精度评价 3 结果分析3.2 日蒸散反演结果及变化3.3 不同土地利用类型蒸散特征分析 4 结论与讨论 摘要…

electron Tab加载动画开启和关闭

记个开发中的bug&#xff0c;以此为鉴。眼懒得时候手勤快点儿&#xff0c;不要想当然&#xff01;&#xff01;&#xff01; 没有转载的价值&#xff0c;请勿转载搬运呦。 WebContents API&#xff1a; Event: did-finish-load​ 导航完成时触发&#xff0c;即选项卡的旋转…

Redis 数据类型及其常用命令二(bitmap、geo、hyperloglog、bitfield、stream)

上文中我们介绍了Redis常使用的5中数据类型&#xff0c;对于一些特殊的场景&#xff0c;我们需要使用特殊的数据类型&#xff0c;本文将详细介绍5种特殊的数据类型。 1、bitmap 类型 用String类型作为底层数据结构实现的一种统计二值状态的数据类型。位图本质是数组&#xff0…

Netty是如何解决JDK中的Selector的bug的?

Selector BUG: JDK NIO的BUG, 例如臭名昭著的epoll bug&#xff0c;它会导致Selector空轮询&#xff0c;最终导致CPU 100%, 官方声称在JDK 1.6版本的update18修复了该问题&#xff0c;但是直到JDK1.7版本该问题仍旧存在&#xff0c;只不过该BUG发生 概率降低了一些而已&#x…

阿里云备案服务器多少钱一年?

ICP备案服务器太贵了&#xff0c;有便宜的吗&#xff1f;有啊&#xff0c;支持备案的服务器只要61元一年。备案服务器入口 https://t.aliyun.com/U/bLynLC 链接打开后&#xff0c;如下图&#xff1a; 阿里云轻量2核2G3M服务器61元一年 如上图所示&#xff0c;这台61元服务器可以…

【动态规划】【组合数学】1866. 恰有 K 根木棍可以看到的排列数目

作者推荐 【深度优先搜索】【树】【有向图】【推荐】685. 冗余连接 II 本文涉及知识点 动态规划汇总 LeetCode1866. 恰有 K 根木棍可以看到的排列数目 有 n 根长度互不相同的木棍&#xff0c;长度为从 1 到 n 的整数。请你将这些木棍排成一排&#xff0c;并满足从左侧 可以…

Leetcoder Day16| 二叉树 part05

语言&#xff1a;Java/C 513.找树左下角的值 给定一个二叉树的 根节点 root&#xff0c;请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至少有一个节点。 示例 1: 输入: root [2,1,3] 输出: 1示例 2: 输入: [1,2,3,4,null,5,6,null,null,7] 输出: 7 本题需要满足两…

多线程系列(一) -线程技术入门知识讲解

一、简介 在很多场景下&#xff0c;我们经常听到采用多线程编程&#xff0c;能显著的提升程序的执行效率。例如执行大批量数据的插入操作&#xff0c;采用单线程编程进行插入可能需要 30 分钟&#xff0c;采用多线程编程进行插入可能只需要 5 分钟就够了。 既然多线程编程技术…

2024年2月前端技术新动态:迈向现代化的全速前进

随着技术的不断进步&#xff0c;前端领域每月都有新的变化和挑战。2024年2月&#xff0c;我们见证了几项重大的技术更新&#xff0c;从Deno的性能提升到Turborepo的重大改进&#xff0c;再到jQuery 4.0.0 Beta的发布&#xff0c;这些变化不仅标志着前端开发向着更现代化、更高效…

Eclipse 设置 tab width 为 4 个空格 (spaces)

Eclipse 设置 tab width 为 4 个空格 [spaces] References Window -> Preferences -> General -> Editors -> Text Editors&#xff0c;选中右侧的 Insert space for tabs. Apply and Close. Window -> Preference -> C -> Code Style -> Formatter&a…

python使用工厂模式和策略模式实现读文件、分析内容功能

当涉及到在 Python 中创建类以及使用设计模式来实现读取文件和分析内容的功能时&#xff0c;我们可以考虑使用工厂模式和策略模式的结合。下面是一个简单的示例&#xff0c;演示如何通过创建类和使用设计模式来实现这一功能&#xff1a; # 工厂模式&#xff1a;根据不同的分析…

直接选择排序算法

​​​​​​目录 选择排序 SelectSort直接选择排序 整体思路 图解分析 ​ 代码实现 时间复杂度 选择排序 基本思想&#xff1a; 每一次从待排序的数据元素中选出最小&#xff08;或最大&#xff09;的一个元素&#xff0c;存放在序列的起始位置&#xff0c;直到全部待排…

Stable Diffusion ComfyUI安装详细教程

上一篇文章介绍了sd-webui的安装教程&#xff0c;但学习一下ComfyUI这种节点流程式的对理解AI绘画有较大帮助&#xff0c;而且后期排查错误会更加方便&#xff0c;熟练后用这种方式做AI绘画可玩性会更多。 文章目录 一、安装包说明二、安装文件介绍三、安装步骤四、汉化五、云主…

Mysql 权限与安全管理

0 引言 MySQL是一个多用户数据库&#xff0c;具有功能强大的访问控制系统&#xff0c;可以为不同用户指定允许的权限。MySQL用户可以分为普通用户和root用户。root用户是超级管理员&#xff0c;拥有所有权限&#xff0c;包括创建用户、删除用户和修改用户的密码等管理权限&…

qt-交通路口仿真

qt-交通路口仿真 一、演示效果二、核心代码三、程序链接 一、演示效果 二、核心代码 #include "generator.h"Generator::Generator(SimulationScene *scene):m_scene(scene),m_mode(VEHICLEMETHOD::GO_THROUGH),m_running_state(false),m_VisionOn(false),m_IsInter…

AI时代教师如何修炼内功

AI时代教师如何修炼内功 How Teachers Can Cultivate Their Inner Strength in the Age of AI 在AI时代&#xff0c;教师的角色和职责正在经历前所未有的变革。随着人工智能技术的不断进步&#xff0c;教育领域出现了许多新的工具和方法&#xff0c;这些新发展要求教师提升自身…