椋鸟C语言笔记#21:函数指针、函数指针数组(转移表)、typedef及其必要性

LVGL v8.3 图片显示与解码缓存实战:PNG 上屏、C 数组与文件双方案 LVGL v8.3 图片两种存储方式、PNG/JPG 上屏解码器挂载、LV_IMG_CACHE_DEF_SIZE 缓存调优、手动预解码头像有效性判断,及"缓存被动画清空"真实踩坑。 阅读详情

萌新的学习笔记,写错了恳请斧正。


目录

函数指针

函数的地址

函数指针的创建

函数地址的使用

typedef及其必要性

typedef

typedef的必要性

函数指针数组(转移表)


函数指针

函数指针,顾名思义,就是存放函数地址的指针

函数的地址

函数也有地址吗?我们来看一段代码:

#include <stdio.h>

void func()
{
    ;
}

int main()
{
    printf(" func = %p\n", func );
    printf("&func = %p\n", &func);
    return 0;
}

在一次运行中其结果为:

 func = 00007FF60C0211A4
&func = 00007FF60C0211A4

可见,函数是有地址的。而且和数组一样,可以用取地址操作符获取其地址,而且函数名本身也代表了其地址。那我们得到了函数的地址有什么用呢?

我们可以通过地址来调用函数,这部分下面讲。

函数指针的创建
int (*pf) (int, float);
int (*pf) (int a, float b);    //一个意思,都行

上方就是创建了一个名叫pf的函数指针,而这个函数的返回值就是前面的int,函数的变量为后面括号里的int与float。其实我们可以发现,定义函数指针的语句与声明函数的语句的区别只有在函数名/函数指针名外面包上一个括号并加一个星号

而这个函数指针变量的变量类型是:

int (*) (int, float)
函数地址的使用

既然得到了函数的地址,我们就可以用地址来调用函数。其实这里写法与直接调用函数类似,或者不如说直接调用函数就可以理解为函数名是一个函数指针:

#include <stdio.h>

int test()
{
    return 1;
}

int main()
{
    int a = test();
    int (*pf)() = &test;
    int b = pf();
    printf("%d", a);
    printf("%d", b);
    return 0;
}

这里输出结果a=b=1,我们发现函数指针可以直接用来调用函数。

这具体能给我们的代码带来什么变化呢?下面讲。

typedef及其必要性

typedef

typedef可以用来给类型名起“绰号”,让代码更易读易写:

typedef unsigned long long ull;

这里就是给unsigned long long起了一个叫ull的“绰号”,之后我们就能直接使用ull了,比如直接定义unsigned long long类型的变量:

ull a = 1145141919810;

我们也可以给指针类型和数组类型起“绰号”:

typedef int* pt_i;
typedef int[5] pt_arr;

同样的,也可以给指针数组、数组指针“起绰号”,但是复杂一点。

我们假设指针数组的类型是(int(*)[9]),数组指针的类型是(int*[9])

我们需要像定义这两种类型变量一样,把“别名”放在原本变量名的位置,如:

typedef int (*type1)[9];
typedef int *type2[9];

这里就成功的起了type1和type2两个“绰号”。

那么再试试给函数指针“起绰号”,其过程和数组指针类似

我们假设函数指针的类型是(int (*) (int, float)):

typedef int (*type3) (int, float);
typedef的必要性

我们先看个语句:

 (*(void (*)())0)();

这个代码十分晦涩,易读性很差。

那如果写成这样呢:

typedef void(*type_pfun)();
type_pfun pfun;
pfun = (type_pfun)0;
(*pfun)();

我们可以看到,这四条语句就好理解多了:

第一行将一个参数为空返回为空函数指针的类型起绰号为type_pfun

第二行定义了一个type_pfun类型的函数指针pfun

第三行将0强制类型转换为type_pfun,并赋值给pfun

第四行解引用pfun,调用这个无输入无输出的函数

四行合起来就是去调用一个0地址处的无参数无输出的函数

这里就能明显的看出typedef对代码易读性的重要作用了。

再看一个:

void (*signal(int , void(*)(int)))(int);

同样的,可以把代码拆为:

typedef void (*type_pfun)(int);
type_pfun signal(int, type_pfun);

这样,我们明显能看出,其实就是声明了一个叫signal的函数。这个函数的返回类型是一个函数指针,参数也有一个函数指针。而这两个函数指针都指向了有一个int类型参数无返回值的函数。

函数指针数组(转移表)

函数指针数组,也叫转移表,就是存放函数指针的数组。

和前面指针数组的逻辑类似,要让最终定义出来的是数组,就需要让变量名先与方括号结合:

int (*pfunarr[6])();

这就定义了一个叫pfunarr的数组,数组长度6,存放(int(*)())类型的函数指针

其使用方式与正常的数组一致,我们可以利用其实现在不同条件下调用不同的函数

比方说,在用户选择的模式不同时进行不同计算的计算器:

#include <stdio.h>

typedef int (*f_calc)(int, int);

void menu()
{
	printf("*******************\n");
	printf("***1.ADD***4.DIV***\n");
	printf("***2.SUB***5.MOD***\n");
	printf("***3.MUL***0.exit**\n");
	printf("*******************\n");
}

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 MOD(int a, int b)
{
	return a % b;
}


int main()
{
	int m = 0, n = 0, mode = 0;
	f_calc calc[6] = {NULL, ADD, SUB, MUL, DIV, MOD};
	menu();
	printf("Type in calc mode:");
	scanf("%d", &mode);
	printf("Type in the two calc number:");
	scanf("%d%d", &m, &n);
	printf("The answer is: %d\n", calc[mode](m, n));
	return 0;
}

第28篇 sw放样特征矩形-圆-矩形学习笔记 本例演示三轮廓放样:先画中心对齐的100×100矩形草图,再在偏移100的基准面上绘制圆,最后在另一基准面画矩形。通过依次选择三个轮廓并正确设置连接点,实现矩形→圆→矩形的平滑过渡,注意连接点位置避免扭曲。 阅读详情

相关推荐

Zemax API 与 Python 的独立应用程序

Zemax 提供了多个 python 示例代码,位于 Documents\Zemax\ZOS-API Sample Code\Python。使用以下代码,它们保存在 ZOS 文件目录中:/Documents\Zemax\Samples\API\Python。此代码块定位已安装的 OpticStudio 版本,确定根目录,创建命名空间和类,加载局部变量。如果定义的镜头需要一些特殊的编辑,例如反转,一种快速方法是从位于编程选项卡的 ZOS-API 语法帮助中找到相应的命令。重新运行整个代码块,镜头方向会改变。

jkh920184196的博客 1977

static 的三种用法:C 语言里一个关键字的三张面孔

本文系统讲解 C 语言中 static 关键字的三种用法:修饰局部变量延长生命周期、修饰全局变量与函数限制作用域到本文件。通过一个包含三个文件的完整工程示例对照演示,并从存储期、作用域与链接性三个属性解释其统一原理,最后补充单元测试框架偏爱 static 函数的工程实践。

大模型全栈工程师 · Thanks_ks 312

【学习体会】Lighttools8.4.0:简单光学系统实例

添加球型光源(SphereSource)和表面接收器: 对光线模拟的参数进行设置: 光线追踪-模拟输入 要追踪的光线总数,决定模拟的准确度,总数越多,准确度越高,当然耗时更多 预览光线数量是模拟之后可以看到的示意光线(黑线),一般是100~1000,随意设置 点击,开始模拟: (模拟结果) 如果光线太多,则会出现,可以看到剩余时间 照度分析: 分析-照度显示-光栅图表 ...

LeonJin的博客 1万+

MySQL建库建表操作学习笔记

SQL(Structured Query Language,结构化查询语言)是用于在关系型数据库上执行数据操作、数据检索以及数据维护的标准语言。:用于定义对数据库对象(库、表、列、索引)的操作,如 CREATE、DROP、ALTER、RENAME、TRUNCATE 等。保存可变长度的字符串(可包含字母、数字以及特殊字 符)。:用于定义对数据库记录的操作,如 INSERT、DELETE、UPDATE、SELECT 等。:用于定义对数据库、表、字段、用户的访问权限和安全级别,如 GRANT、REVOKE 等。

Eternitycai的博客 224

MySQL8.2.0下载安装

4、点击No thanks,just start my download,就是只是开始下载的意思,点击下载,等待下载完成。5、新建空白行,或直接双击紧挨的空白行,把复制的mysql的安装路径bin路径复制粘贴过来,确定,确定,确定。1、上面点击finish后,自动勾选了run mysql配置,自动会打开配置页面,点击Next。1、双击安装包,进入安装流程,勾选我同意 I accept,next。2、根据自己需要选择,我选的第二个,可以自己改安装路径。2、默认,点击Next,记住默认端口3306。

m0_59681797的博客 1万+

pynq-z2 HLS开发

定制Overlay一.用HLS生成一个定制IP功啊啊是合理的创建标题,有助于目录的生成如何改变是式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入 一.用HLS生成一个定制IP ...

qq_38769280的博客 4156

选型笔记:Type‑C 扩展坞方案评估|DP1.4 转 HDMI2.0 桥接芯片 GSV2201S@ACP

本文记录 GSV2201S 这款 DP1.4a 转 HDMI2.0 桥接芯片评估,梳理视频、HDCP、PD 集成能力,总结 Type‑C 转接 Dongle、扩展坞方案的适配边界,以及差分走线、PD 时序、HDCP 握手等高频调试问题,为 C 口视频转接方案选型提供参考。

ACP广源盛的博客 221

AutoSAR_BSW高阶 7. Signal Group 信号组

Autosar BSW的高级配置是实现复杂汽车电子系统的关键步骤之一。通过合理配置信号组和使用适当的参数,您可以提高系统性能,确保数据的可靠传输。在本博客中,我们深入探讨了信号组的概念和高级配置参数,并提供了示例代码,希望这些信息能够帮助您更好地理解和应用Autosar BSW的高级配置。如果您在配置过程中遇到任何问题,不妨寻求专业支持,以确保您的汽车电子系统能够顺利运行。Autosar COM 模块是一个广泛应用于汽车行业的关键技术,它使不同的电子控制单元能够有效地通信和协作。

一直在水些技术小文 662

新概念英语第一册 · 词法笔记

以《新概念英语第一册》为范围,梳理 10 类词性中的 8 类:名词的数与所有格、冠词、代词、形容词副词比较级、数词与时间、介词、动词四类与 have 的四种用法、情态动词与不定式,附易错 TOP12 与课次顺序。

Ep流苏的博客 203

继电器管理策略(二)

介绍了电池管理系统中的继电器管理,包含控制和诊断

manjixingkong1234的专栏 419

数据挖掘实战-基于决策树算法构建北京市空气质量预测模型

通过分析这些数据,我们将利用决策树算法建立预测模型。决策树算法具有直观易懂、分类效果好等优点,适合用于此类预测问题。我们将采用适当的方法对模型进行训练和优化,以提高预测精度。最终,我们将评估模型的预测效果,并探讨其在实际应用中的可行性和潜在价值。希望通过本实验,能为北京市的空气质量改善工作提供一定的支持。通过基于决策树算法构建的北京市空气质量预测模型的实验研究,我们在多方面取得了显著的进展。首先,我们成功地整合了来自气象、环保、交通等多个领域的大量数据,形成了一个全面而综合的空气质量分析框架。

m0_64336780的博客 2万+

2026小红书小工具怎么制作:纯前端 ZIP 打包、沙箱限制与笔记挂载流程

小红书小工具制作的核心不是复杂开发,而是把需求压缩成纯前端轻交互,并按平台要求完成 ZIP 交付。适合做的方向是测试、计算器、生成器、学习小测和记录工具;不适合做的方向是账号体系、云端数据、支付和远程接口。制作时先确认沙箱限制,再整理输入、计算、输出链路,最后通过 Builder Hub 提交审核并挂载笔记。在需求简单、素材较少的情况下,十几分钟做出一个可用的小工具是现实路径,袋马就是一个选择。

qq_39308835的博客 285

HDOCK 蛋白蛋白对接软件使用;LZerD、pyDock、ClusPro网页在线对接

参考:hdock支持蛋白与蛋白,也支持蛋白与核酸对接计算。

weixin_42357472的博客 1万+

闪光灯笔记

主体后常亮补光,相机快门速度两秒,相机固定在三脚架上,让主体保持不动,按下快门之后主体周围晃动灯棒。特点:人物清晰,背景车流灯光拖在人物身后,氛围感强,就是 A7R3 + 神牛外帘同步的目标效果。总时长 = 8÷10=0.8s 👉 A7R3 相机:M 档,快门 1s,f/8,ISO100。上图:前帘同步,车向前行驶,光轨跑到车头前面,看着很怪。例:6 次,4Hz → 6÷4=1.5s → 相机快门设置≥1.5s,推荐 2s。缺点(慢速快门拍运动物体):闪光先把人定住,之后人物继续移动,在传感器上,

oDianZi1234567的博客 276

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

【Linux】APT 本地 deb 安装与 `-f` 参数总结笔记

apt install ./xx.deb 可自动解析并安装依赖,无需 -f;-f 仅用于修复已损坏的依赖状态,非首次安装时必需。apt install -f 可单独运行,修复 broken dependencies。两者职责不同:前者是安装与依赖解决,后者是故障修复。完全离线时需提前准备依赖包或本地源。

hknaruto的专栏 211

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

排序算法深度笔记(下):非比较类排序的线性突破与工程边界

排序算法时间复杂度额外空间复杂度稳定性是否基于比较选择排序O(N^2)(O(1))不稳定是冒泡排序O(N^2)(O(1))稳定是插入排序O(N^2)(O(1))稳定是归并排序O(N\log N)(O(N))稳定是快速排序O(N\log N)O(log N)不稳定是堆排序O(N\log N)O(1)不稳定是计数排序(O(N + M))O(M))稳定否基数排序O(N)稳定否桶排序平均O(N) / 最坏O(N^2)

2401_87069538的博客 567

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

【LTE L3 笔记 10】LTE物理信道-PUCCH、PUSCH

课程来源:B站《【2022】华为HCIA-LTE无线工程师认证学习中级视频》笔记为个人整理,含课件截图,仅供学习交流。

lyouhuan的博客 179

邓明 Agent 系统面试-意图识别学习笔记

不要只是做意图识别而不做测评,就好像要评估 RAG 准确性,在接口服务要测试响应时延,超时控制等等,这里也要关注意图识别准确率,如果面试官认为项目指标太高是在吹牛,关键就是回答因为 Agent 解决的是特定领域的意图识别,识别场景单一,另外就是因为用户输入相对简单。意图识别影响 prompt/spec 的加载,意图识别影响上下文组织,意图识别影响工具选择,意图识别影响 prompt 建议,意图识别得到的意图不是让模型随机生成而是候选类别里去做选择。2.意图识别的原因,以及意图识别得到的是什么?

m0_57222081的博客 215

【LTE L3 笔记 05】LTE同步信号

课程来源:B站《【2022】华为HCIA-LTE无线工程师认证学习中级视频》笔记为个人整理,含课件截图,仅供学习交流。

lyouhuan的博客 114

Java 多态 学习笔记

多态是面向对象编程的重要特性,指同一操作作用于不同对象时产生不同行为。其核心在于“父类引用指向子类对象”,结合方法重写实现运行时动态绑定。多态使代码更灵活、可扩展,如用Person p = new Student();统一处理各类人员注册,无需修改调用逻辑。但多态无法直接调用子类特有方法,需通过instanceof判断并强制转换。编译时看左边(类型),运行时看右边(实际对象),实现解耦与维护便利。

AA_AA114514的博客 358

硬件选型笔记:HDMI2.0 转 DP1.4 主动桥接方案 GSV2125D@ACP 评估

本文记录 GSV2125D HDMI2.0 转 DP1.4 主动桥芯片规格与工程调试问题,适合便携屏、HDMI 转 DP 转接器、图像采集板前期方案评估,重点关注 DP 链路训练、EDID、HDCP 兼容性边界。

ACP广源盛的博客 290

Arduino-MEGA-ESP单片机理论课笔记-06温湿度-07时间-延时定时-2026

本文解析了DHT11温湿度传感器的Arduino代码,逐行讲解了库引入、引脚定义、传感器初始化及数据读取流程。重点说明了delay(1000)导致阻塞的问题,并提出使用millis()实现非阻塞定时,将采样间隔改为2秒,提升程序响应性。同时建议增加isnan()错误检测、优化串口输出格式,确保数据稳定可靠。

zhangrelay的专栏 336

#SQLite 数据库笔记一:(概念 / 终端指令 / SQL 语句 / C 编程 / 回调函数)

数据库 = 数据的仓库,假设数据是海量。能力说明存储数据持久化保存,程序退出数据还在统计数据、分组、排序数据管理增、删、改、查(CRUD)嵌入式设备上也会用数据库(单片机网关、路由器、工业 HMI 都常见),因为 sqlite 体积小、无需服务进程、单文件即可。数据库 = 库 > 表 > 记录(行) > 字段(列)sqlite3 = 开源、C 写的、单文件、免安装、最多 2T 的嵌入式关系型数据库。

lwq20051110的博客 203

【学习笔记】51单片机 模块化编程

模块化编程:把各个模块的代码放在不同的c文件里,在.h文件里提供外部可调用函数的声明,在其他.c文件想使用其中的代码时,只需要#include"xxx.h"文件即可。传统方式编程:所有的函数均放在main.c中,若使用的模块比较多,则一个文件内会有很多的代码,不利于代码组织和管理,而且很影响编程者的思路。使用LCD602液晶屏作为调试窗口,提供类似printf函数的功能,可实时观察单片机内部数据的变换情况,便于调试和演示。使用到的.h文件必须要放在编译器可寻找到的地方(工程文件夹根目录,安全目录,自定义)

2601_96469072的博客 226

本地笔记的持久化:选区锚点、条目关联与内容升级时的迁移

离线典籍类应用里,读者产生的数据常常被当作附属功能处理:选中一句话、写两句理解,看起来只是往数据库里插一行。真正麻烦的是这些数据必须与正文长期对齐——正文会随内容包升级而变动,而用户写下的东西不能跟着失效。本文以一款纯本地运行的鸿蒙知识库为例,记录实现侧几个容易踩坑的取舍,与检索链路无关。

m0_61869851的博客 192

【论文阅读笔记】Score Centering 如何稳定存在训练-推理不匹配的强化学习

大语言模型强化学习里,负责生成 rollout 的 sampler 和负责计算梯度的 trainer 往往不是完全同一个数值系统,二者之间存在训练-推理不匹配(training-inference mismatch,TIM)

iiiiii11的博客 482
上一篇: 椋鸟C语言笔记#20:指针数组、指针模拟二维数组、数组指针、二维数组传参的本质、字符指针与字符串
下一篇: 椋鸟C语言笔记#22:回调函数、泛式编程、qsort
椋鸟Starling
博客等级 码龄3年 447粉丝 57原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

椋鸟Starling

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值