【C语言进阶篇】指针都学完了吧!那回调函数的应用我不允许还有人不会!
文章目录
- 📋 前言
- 💬 函数指针数组
- 💭 函数指针数组的定义
- 💭 函数指针数组的应用 —— 转移表
- 💻 代码改进
- 💬 指向函数指针数组的指针
- 💬 回调函数
- 💭 利用回调函数进行代码改进
- 📝全篇总结
📋 前言
🌈hello! 各位宝子们大家好啊,上节课我们学习了函数指针,而函数指针有一个非常大的用途就是实现回调函数!
⛳️在了解回调函数之前我们还需要学习一下函数指针数组的概念!
📚本期文章收录在《C语言进阶篇》,大家有兴趣可以看看呐!
⛺️ 欢迎铁汁们 ✔️ 点赞 👍 收藏 ⭐留言 📝!
🔥 注:VS2022 等C语言学习工具都在《学习工具专栏》, 还有各种实用调试技巧有兴趣可以去看看!
💬 函数指针数组
⛳️既然我们有指针数组的概念,那么函数本身也是一个地址啊!函数指针数组 和 指针数组只不过多了函数俩字 ,那么函数指针数组该如何定义呢?
💭 函数指针数组的定义
⛳️假设我们要写一个计算器,加减乘除4个部分的函数但是函数参数都是一样的。想把他放到一个函数指针数组里面该怎么办呢?
- 函数指针我们知道怎么定义但是,加了数组俩字该怎么定义呢?
📚 代码演示:
#include <stdio.h>int Sum(int x, int y)
{return x + y;
}
int Sub(int x, int y)
{return x - y;
}
int Mul(int x, int y)
{return x * y;
}
int Div(int x, int y)
{return x / y;
}int main()
{int (*pf1)(int, int) = Sum;int (*pf2)(int, int) = Sub;int (*pf3)(int, int) = Mul;int (*pf4)(int, int) = Div;//函数指针数组int (*pfArr[4])(int, int) = {Sum,Sub,Mul,Div};return 0;
}
大家看函数指针数组就是这样定义的,由于【】号的结合性比 * 号高所以 pfArr就先和【】号结合,所以pfArr[ 4 ] 表示这个指针是个数组。
*号则代表pfArr[ 4 ] 是个指针- int(*)(int , int ) 代表了他是个函数指针类型的
- 所以 nt (*pfArr[4])(int, int) 是函数指针数组类型的
💭 函数指针数组的应用 —— 转移表
前面写的计算器,如果按照我们以前思路写的代码会非常冗余,那么我们学了函数指针数组有没有可能吧代码优化下嘛?
- 这时就要用到函数指针数组的应用 —— 转移表了
- 我们来看一下:
📚 未改变前:
#include <stdio.h>int Sum(int x, int y)
{return x + y;
}
int Sub(int x, int y)
{return x - y;
}
int Mul(int x, int y)
{return x * y;
}
int Div(int x, int y)
{return x / y;
}void menu()
{printf("***********************\n");printf("***** 1:add 2:sub ***** \n");printf("***** 3:mul 4:div *****\n");printf("***** 0.exit *****\n");printf("***********************\n");
}
int main()
{int input = 0;int x = 0;int y = 0;int ret = 0;do{menu();printf("请输入->");scanf("%d", &input);switch (input){case 1:printf("请输入俩个操作数:");scanf("%d %d", &x, &y);ret = Sum(x, y);printf("%d\n", ret);break;case 2:printf("请输入俩个操作数:");scanf("%d %d", &x, &y);ret = Sub(x, y);printf("%d\n", ret);break;case 3:printf("请输入俩个操作数:");scanf("%d %d", &x, &y);ret = Mul(x, y);printf("%d\n", ret);break;case 4:printf("请输入俩个操作数:");scanf("%d %d", &x, &y);ret = Div(x, y);printf("%d\n", ret);break;case 0:printf("退出计算器!\n");break;default:printf("选择错误,请重新输入!\n");break;}} while (input);return 0;
}
💻 代码改进
这里我们就带代码进行了改进,使得main() 函数里面代码量大大减少。
- 这里由于我们选择时的数字要和数组下标一样
- 所以我们填充一个空指针
NULL让每个数组下标和我们的操作数对应!
#include <stdio.h>
int Sum(int x, int y)
{return x + y;
}
int Sub(int x, int y)
{return x - y;
}
int Mul(int x, int y)
{return x * y;
}
int Div(int x, int y)
{return x / y;
}void menu()
{printf("***********************\n");printf("***** 1:add 2:sub ***** \n");printf("***** 3:mul 4:div *****\n");printf("***** 0.exit *****\n");printf("***********************\n");
}
int main()
{int input = 0;int x = 0;int y = 0;int ret = 0;do{menu();printf("请输入->");scanf("%d", &input);//函数指针数组 —— 转移表int(*pfArr[5])(int, int) = {NULL ,Sum,Sub,Mul,Div};if (input >= 1 && input <= 4){printf("请输入操作数:");scanf("%d %d", &x, &y);ret = pfArr[input](x, y);printf("%d\n", ret);}else if (input == 0){return 0;}else{printf("选择错误请重新输入;\n");}} while (input);return 0;
}
💬 指向函数指针数组的指针
这里我们又进行了一遍套娃,指针数组既然我们能接收那么。有没有指向函数指针数组的指针呢?答案是有的。
- 数组指针类型 int (*p)[ 5 ]
- 函数指针类型 int (*pf)(int, int)
- 函数指针数组类型 int (*pf [ 5 ])(int, int)
- 指向函数指针数组的指针 int (*(*pf)[ 5 ])(int, int)
这里我们可以怎么样理解呢?首先在指向函数指针数组的指针不要硬写在我们函数指针数组的类型上进行改变!
- 函数指针数组类型 int (*pf [ 5 ])(int, int)
- 我们首选需要一个指向函数指针数组的指针
- 那么pf 就不能和左边的
*结合 因为 int (* [ 5 ])(int, int) 代表了函数指针数组类型而我们想要接收他就需要一个指针 *pf - 那么把它括起来就是指向函数指针数组的指针了
- int (*(*pf)[ 5 ])(int, int)
📚 代码演示:

💬 回调函数
⛳️回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
- 怎么应用呢?函数指针的应用其实就是回调函数
- 我们前面改进计算器的的时候用函数指针数组进行改进
- 那么我们下面就对计算器用回调函数的方式进行改进
回调函数我的理解就是通过函数指针的方式接收函数的地址,从而调用它。让一个函数可以调用多个同类型的函数的功能在特定的情况给我传输函数地址从而使用它。
- 上面计算器的实现用switch 语句实现的时候每一个case语句都是相同的除了函数的实现方法不同。这样就导致代码过于冗余!

而这我们就可以用一个回调函数进行改进,让这些代码都在一个函数里面。每次使用那个函数直接传送给我们的地址就行了!
📚 代码演示:
这样铁汁们看是不是就避免的代码冗余的问题,我们只需要把函数地址传过来就可以了,输入什么选择就传什么函数从而去调用他!
void calc(int (*pf)(int x, int y))
{int x = 0;int y = 0;printf("请输入操作数;");scanf("%d %d", &x, &y);int ret = pf(x, y);printf("%d\n", ret);
}

💭 利用回调函数进行代码改进
📚 代码演示:
#include <stdio.h>
int Sum(int x, int y)
{return x + y;
}
int Sub(int x, int y)
{return x - y;
}
int Mul(int x, int y)
{return x * y;
}
int Div(int x, int y)
{return x / y;
}void menu()
{printf("***********************\n");printf("***** 1:add 2:sub ***** \n");printf("***** 3:mul 4:div *****\n");printf("***** 0.exit *****\n");printf("***********************\n");
}
void calc(int (*pf)(int x, int y))
{int x = 0;int y = 0;printf("请输入操作数;");scanf("%d %d", &x, &y);int ret = pf(x, y);printf("%d\n", ret);
}
int main()
{int input = 0;do{menu();printf("请输入->");scanf("%d", &input);switch (input){case 1:calc(Sum);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;
}
📝全篇总结
✅ 归纳:
好了以上就是回调函数的使用和讲解以及函数指针数组的概念大家好好理解一下吧!
函数指针数组
函数指针数组的使用
回调函数的概念
回调函数的应用
☁️ 好了今天的知识全是干货不知道各位铁汁们学到了没有呢!快拿去用吧!
看到这里了还不给博主扣个:
⛳️ 点赞☀️收藏 ⭐️ 关注!
💛 💙 💜 ❤️ 💚💓 💗 💕 💞 💘 💖
拜托拜托这个真的很重要!
你们的点赞就是博主更新最大的动力!
有问题可以评论或者私信呢秒回哦。

相关文章:
【C语言进阶篇】指针都学完了吧!那回调函数的应用我不允许还有人不会!
🎬 鸽芷咕:个人主页 🔥 个人专栏:《C语言初阶篇》 《C语言进阶篇》 ⛺️生活的理想,就是为了理想的生活! 文章目录 📋 前言💬 函数指针数组💭 函数指针数组的定义💭 函数指针数组的…...
专注:如何提高专注力和注意力的简要指南
专注力和集中力可能很难掌控的很好。大多数人都想学习如何提高注意力和注意力。但真的做到了?我们生活在一个嘈杂的世界里,不断的分心会使注意力难以集中。 此指南包含有关如何获得并保持专注的研究。我们将分解提升您的思维并关注重要事物背后的理论依…...
Linux查看内存的几种方法
PS的拼接方法 ps aux|head -1;ps aux|grep -v PID|sort -rn -k 4|head 进程的 status 比如说你要查看的进程pid是33123 cat /proc/33123/status VmRSS: 表示占用的物理内存 top PID:进程的ID USER:进程所有者 PR:进程的优先级别&#x…...
selenium定位rect元素
rect元素属性 rect元素的属性如下: x:此属性确定矩形的x坐标。 值类型:| ; 默认值:0 动画:是y:此属性确定矩形的y坐标。 值类型:| ; 默认值:0 动画:是width:…...
uniapp <textarea>组件的踩坑
1、ios真机上,textarea输入时会触发页面其他点击事件, 解决方法:把textarea封装成基础组件,绕过这个bug。 2、使用auto-height属性,安卓真机上,会导致textarea高度异常, 官方人员解释…...
README.md 文档使用 treer 生成树形项目结构
一、前言 前后端编写 README.md 文档的时候,常常需要描写项目的结构,使用 tree 命令生成的目录又不能忽略某个目录,不方便。后来我找到了可以忽略某些目录的 treer命令 ,特此记录一下: 二、使用 treer 生成项目结构 全局安装tr…...
朝花夕拾思维导图怎么画?看看这种绘制方法
朝花夕拾思维导图怎么画?绘制思维导图的好处有很多,首先它可以帮助人们更好地组织和管理知识,提高工作效率和学习效果。其次,绘制思维导图可以帮助人们更好地记忆知识点和理解知识点。总之,绘制思维导图可以帮助人们更…...
Python - OpenCV、OCR识别摄像头中的文字
使用Python3的OpenCV库来识别摄像头中的文字,以及使用OCR(光学字符识别)技术。 安装OpenCV库 在命令行中输入以下命令来安装OpenCV库: pip install opencv-python安装Tesseract OCR库 Tesseract OCR库是一种免费的光学字符识别…...
金融中的数学:贝叶斯公式
1.贝叶斯定理 贝叶斯定理是概率论中的一项重要定理,用于在已知某一事件的条件下,求另一事件发生的概率。它是根据条件概率推导出来的,得名于英国数学家托马斯贝叶斯。 贝叶斯定理可以表示为: 这个式子就是贝叶斯公式,…...
ClickHouse单节点安装配置
四个安装包: 创建clickhouse目录 将安装包解压到该目录 tar -zxvf clickhouse-server-21.9.4.35.tgz -C /opt/module/clickhouse tar -zxvf clickhouse-common-static-21.9.4.35.tgz -C /opt/module/clickhouse tar -zxvf clickhouse-common-static-dbg-21.9.4.35.…...
AtcoderABC231场
A - Water PressureA - Water Pressure 题目大意 假设水压仅取决于深度,在深度为x米时,水压为x/100兆帕斯卡。 现在给定一个深度D米,需要计算在该深度下的水压是多少兆帕斯卡。 思路分析 直接将输入的深度除以100得到水压结果。 时间复杂…...
opengauss数据库快速安装
root执行 groupadd gs useradd -g gs gs passwd gs mkdir -p /opt/software/openGauss sudo chown gs:gs /opt/software/openGauss chmod 700 /opt/software/openGauss gs执行 上传文件到/home/gs目录下 tar -jxf openGauss-x.x.x-openEuler-64bit.tar.bz2 -C /opt/software/o…...
前端中的LocalStorage和SessionStorage
在前端开发中,常常需要在浏览器端保存数据,以便在页面刷新或跳转时能够保留数据或状态。在这种情况下,可以使用Web Storage API中的LocalStorage和SessionStorage来实现数据的存储。它们都是HTML5提供的本地存储解决方案,可以在浏…...
论文工具——写论文好用的绘图工具(甘特图+流程图+网络模型图+泳道图)
文章目录 引言正文手动画图的在线画图工具tldraw开源免费ProcessOnDraw.io 网络模型图工具NN-SVG设置参数自动生成Netron上传模型自动生成PlotNeuralNet编码生成 总结 引言 在写HiFi-GAN论文的代码阅读过程中,我发现仅仅通过文字来描述网络结构,不够详细…...
Vite构建的vue3项目修改网站标题和图标
1.准备一张.ico后缀的图片,这里推荐文件转换器,可以将常见的图片格式转为.ico格式图片。 2.修改网站标题和图标 网站的标题和图标都可以在项目根路径下的index.html下修改。 2.1 网站标题修改<title>标签体内容即可。 2.2 网站图标修改如图<…...
平安私人银行受邀慈善服务高质量发展会议,分享慈善规划服务
近日,中华慈善总会家风传承与慈善信托委员会成立仪式,以及由中华慈善总会、中国银行业协会联合发起的“慈善顾问赋能计划”启动仪式在北京举行。平安私人银行受邀参会并分享慈善规划服务,平安私人银行慈善业务总监王英及平安私人银行客户、“…...
MySQL主从复制、读写分离
一、前言二、主从复制原理2.1 MySQL复制类型2.2 MySQL主从复制工作过程2.3 MySQL的四种同步方式2.3.1 异步复制(MySQL默认)2.3.2 同步复制2.3.3 半同步复制(企业常用)2.3.4 增强半同步复制 2.4 MySQL主从复制延迟原因和优化方法2.…...
Redis配置与优化
目录 一、关系数据库与非关系型数据库 1、关系型数据库 2、非关系型数据库 3、关系型数据库和非关系型数据库区别 1、数据存储方式不同 2、扩展方式不同 3、对事务性的支持不同 二、Redis 1、简介 2、优点 3、缺点 4、使用场景 5、哪些数据适合放入缓存中 6、为什…...
leetCode刷题记录3-面试经典150题
文章目录 不要摆,没事干就刷题,只有好处,没有坏处,实在不行,看看竞赛题面试经典 150 题80. 删除有序数组中的重复项 II189. 轮转数组122. 买卖股票的最佳时机 II 不要摆,没事干就刷题,只有好处&…...
MySQL优化(面试)
文章目录 通信优化查询缓存语法解析及查询优化器查询优化器的策略 性能优化建议数据类型优化索引优化 优化关联查询优化limit分页对于varchar end mysql查询过程: 客户端向MySQL服务器发送一条查询请求服务器首先检查查询缓存,如果命中缓存,则立刻返回存…...
机器学习与深度学习在地球物理勘探中的应用:基于电阻率数据预测极化率模型
1. 项目概述与核心价值在花岗岩这类地质条件复杂的地区搞勘探,最头疼的就是地下情况“看不清”。传统的电阻率(ERT)和激发极化(IP)联合反演,就像用一把刻度模糊的尺子去量一块表面坑洼不平的石头——面对高…...
DeepSeek基准测试避坑手册:92%开发者忽略的4大陷阱——硬件配置偏差、tokenizer不一致、batch size幻觉、温度值污染
更多请点击: https://codechina.net 第一章:DeepSeek基准测试避坑手册:92%开发者忽略的4大陷阱——硬件配置偏差、tokenizer不一致、batch size幻觉、温度值污染 硬件配置偏差:GPU显存与计算精度的隐性干扰 在A100(8…...
从入门到实践:EEG公开数据集分类与应用场景全解析
1. EEG公开数据集入门指南刚接触脑电信号分析的研究者,常常会被一个问题困扰:"我应该从哪里获取可靠的EEG数据?"作为一个在这个领域摸爬滚打多年的研究者,我完全理解这种困惑。记得我第一次接触EEG研究时,光…...
XML 服务器
XML 服务器 引言 XML(可扩展标记语言)服务器在现代互联网技术中扮演着至关重要的角色。它为数据的传输和处理提供了灵活且高效的方式。本文将深入探讨XML服务器的概念、工作原理、应用场景及其在软件开发中的重要性。 什么是XML服务器? XML服务器是一种用于存储、处理和…...
从模糊到电影级景深:Midjourney + Topaz Gigapixel联调方案(含LUT预设包+PSD分层模板)
更多请点击: https://codechina.net 第一章:从模糊到电影级景深:Midjourney Topaz Gigapixel联调方案(含LUT预设包PSD分层模板) 当Midjourney生成的图像存在主体边缘柔化、背景层次缺失或分辨率不足等问题时…...
别再只比参数了!从插件生态到中文优化,聊聊ChatGPT和文心一言的“隐形”差异
超越参数之争:ChatGPT与文心一言的生态与本土化实战解析 当技术评测文章还在反复比较模型参数量与发布时间时,真正影响日常工作效率的往往是那些未被量化的"软实力"。本文将从插件生态构建与中文场景优化两个维度,带您重新认识这两…...
Facebook登录协议逆向解析:appsecret_proof与e2e加密机制
1. 这不是“爬虫教程”,而是一次对现代Web身份协议的解剖实验你有没有试过,在调试一个Facebook登录集成时,浏览器Network面板里突然冒出一串带sig、access_token、e2e、c_user的请求,参数长度动辄上千字符,加密方式五花…...
星露谷物语SMAPI模组加载器:从新手到专家的完整使用指南
星露谷物语SMAPI模组加载器:从新手到专家的完整使用指南 【免费下载链接】SMAPI The modding API for Stardew Valley. 项目地址: https://gitcode.com/gh_mirrors/smap/SMAPI 星露谷物语SMAPI模组加载器是官方推荐的模组API,它为玩家和开发者提供…...
MPC Video Renderer技术解析:DirectShow硬件加速渲染器的实现原理与深度剖析
MPC Video Renderer技术解析:DirectShow硬件加速渲染器的实现原理与深度剖析 【免费下载链接】VideoRenderer Внешний видео-рендерер 项目地址: https://gitcode.com/gh_mirrors/vi/VideoRenderer MPC Video Renderer是一款基于GPL v3协…...
解决WSL中RViz全屏闪烁和字体缩小情况
针对WSL中,ROS2-humble打开RViz2全屏后,地图闪烁的情况:我从网上找,问了ai,试了很多种方法,终于找到一种适合我的方法,有相同情况的朋友可以试一试,但是不保证你的问题和解决方法与我…...
