指针的介绍3后

1.函数指针变量

1.1函数的地址

void test(int (*arr)[2])
{printf("zl_dfq\n");
}
int main()
{printf("%p\n", test);printf("%p\n", &test);return 0;
}

由上面的程序运行可知:

函数名就是函数的地址

&函数名也可以拿到函数的地址

1.2函数指针变量

1.2.1函数指针变量的引入

学习完整型指针变量,字符指针变量,数组指针变量之后,我们不难推出

函数指针变量就是一个存放函数地址的变量

void test(int a, int b)
{printf("%d\n", a);printf("%d\n", b);
}
int main()
{void(*p)() = test;return 0;
}

指针 p 就拿到了函数 test 的地址

 

1.2.2函数指针变量的书写

 void(*p)(int a, int b) 去掉标识符 p 就是该指针的类型

即,p 指向了一个 void (*) (int a, int b) 型的函数

记忆方法:

(1)

 void(*p)(int a, int b) 如果去掉第一个括号,变为

 void* p(int a, int b)

那么,这将变成一个函数的声明

函数名为 p ,形参为(int a, int b), 返回值为 void*

(2)

注意:

函数指针变量中,函数的

形参按原函数的顺序

可以只写类型,不写形参名

即 void(*p)(int a, int b) ==  void(*p)(int , int )

1.2.3函数指针变量的使用

通过函数指针调用 指针指向的 函数

void test(int a, int b)
{printf("%d\n", a);printf("%d\n", b);
}
int main()
{void(*p)(int a, int b) = test;(*p)(3, 5);return 0;
}

(*p)(3, 5);

p拿到了函数test的地址

*p就拿到了函数, *p == test

此时传参即可

但注意*p要用()括起来,不然p会先于第二个()结合

 

由上面的程序运行发现:

(1)可以通过函数指针直接调用函数

(2)多次解引用指针, 没啥影响

实际上,

(1)编译器是直接通过地址找到函数,并调用的

此时并没有进行, *解引用操作

总结:

(1)

(*p)(3, 5)有解引用的书写 便于理解

p(3, 5)无解引用的书写 简化符号

(2)对于函数名来说,前面的&和*都会被忽略

 1.3 typedef关键字

定义:typedef 关键字被用于为一个已存在的数据类型创建一个新的名称(别名)

用法:

typedef existing_type new_type_name;

注意:

对函数指针和数组指针创建别名时,标识符要放在(*)中

typedef void(*a)(int) ;//right
typedef void(*)(int) a;//err
typedef int(*a)[10] ;//right
typedef int(*)[10] a;//err

1.4两段有趣的代码

1.4.1第一段

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

解析:

(1)粉方框框起来的意思是

这是一个函数指针类型

(2)黑方框框起来的意思是

这将进行显示类型转换

(3)黄方框框起来的意思是

将 0 转换为一个函数指针

(4)红方框框起来的意思是

解引用函数指针,并调用该函数

 1.4.2第二段

 函数返回值是一个函数指针的时候,

函数的书写形式:

 void (* signal(int) )(int); //rightvoid (*  )(int) signal(int);//err

所以请看题:

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

解析:

(1)黑方框框起来的意思是

这是一个函数

(2)粉方框框起来的意思是

函数的返回值是一个函数指针

实在是过于纷乱,使用typedef简化名称

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

代码就简单易懂啦!

2.函数指针数组与转移表

2.1相关含义

函数指针数组就是存放函数指针的数组

 void(*)() p[10]; //err
void(*p[10])();   //right

第二行代码才是正确的函数指针数组的书写形式

标识符[元素个数] 写入 函数指针的(*)中

函数指针数组的用途:转移表

转移表(Jump Table),也叫跳转表,是一种用于实现多分支选择结构的数据结构或技术

转移表通常用于替代复杂的if-else或switch语句

2.2举例之简易计算器的实现

#define _CRT_SECURE_NO_WARNINGS 1
#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;
}
void menu()
{printf("****************************\n");printf("****************************\n");printf("****   1.Add   2.Sub   *****\n");printf("****   3.Mul   4.Div   *****\n");printf("****   0.OUT           *****\n");printf("****************************\n");printf("****************************\n");
}
int main()
{int input;do{menu();printf("请选择:");scanf("%d", &input);int x = 0;int y = 0;switch (input){case 1:printf("请输入两个操作数:");scanf("%d %d", &x, &y);int ret1 = Add(x, y);printf("%d\n", ret1);break;case 2:printf("请输入两个操作数:");scanf("%d %d", &x, &y);int ret2 = Sub(x, y);printf("%d\n", ret2);break;case 3:printf("请输入两个操作数:");scanf("%d %d", &x, &y);int ret3 = Mul(x, y);printf("%d\n", ret3);break;case 4:printf("请输入两个操作数:");scanf("%d %d", &x, &y);int ret4 = Div(x, y);printf("%d\n", ret4);break;case 0:printf("已退出计算器\n");break;default:printf("选择有误,请重新选择\n");}} while (input);return 0;
}

不难发现 switch 语句中 有大量的重复语句,

并且如果加上 & ^ ~ 等计算,会使代码更加冗余

此时想到转移表

只需要修改main 函数部分

int main()
{int (*Funcs[5])(int, int) = { 0, Add, Sub, Mul, Div };int input;do{menu();printf("请选择:");scanf("%d", &input);if (input >= 1 && input <= 4){int x = 0;int y = 0;printf("请输入两个操作数:");scanf("%d %d", &x, &y);int ret = Funcs[input](x, y);printf("%d\n", ret);}else if (input == 0){printf("已退出计算器\n");}else{printf("选择有误,请重新选择\n");}} while (input);return 0;
}

(1)使用函数指针数组中存放每个函数的地址

(2)函数指针数组中,使用 0 占位

使数组下标对应菜单选项

这样以后,代码更加简洁,并且增添都很方便

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于Springboot的智能学习平台系统【附源码】

基于Springboot的智能学习平台系统 效果如下&#xff1a; 系统登陆页面 系统主页面 课程详情页面 论坛页面 考试页面 试卷管理页面 考试记录页面 错题本页面 研究背景 随着互联网技术的普及&#xff0c;人们探索知识的方式逐渐转向数字化平台。传统的教学方法通常局限于固定…

shiro学习五:使用springboot整合shiro。在前面学习四的基础上,增加shiro的缓存机制,源码讲解:认证缓存、授权缓存。

文章目录 前言1. 直接上代码最后在讲解1.1 新增的pom依赖1.2 RedisCache.java1.3 RedisCacheManager.java1.4 jwt的三个类1.5 ShiroConfig.java新增Bean 2. 源码讲解。2.1 shiro 缓存的代码流程。2.2 缓存流程2.2.1 认证和授权简述2.2.2 AuthenticatingRealm.getAuthentication…

网关登录校验

网关登录校验 单体架构时我们只需要完成一次用户登录、身份校验&#xff0c;就可以在所有业务中获取到用户信息。而微服务拆分后&#xff0c;每个微服务都独立部署&#xff0c;不再共享数据。也就意味着每个微服务都需要做登录校验&#xff0c;这显然不可取。 鉴权思路分析 …

【单细胞第二节:单细胞示例数据分析-GSE218208】

GSE218208 1.创建Seurat对象 #untar(“GSE218208_RAW.tar”) rm(list ls()) a data.table::fread("GSM6736629_10x-PBMC-1_ds0.1974_CountMatrix.tsv.gz",data.table F) a[1:4,1:4] library(tidyverse) a$alias:gene str_split(a$alias:gene,":",si…

【已解决】黑马点评项目Redis版本替换过程的数据迁移

黑马点评项目Redis版本替换过程的数据迁移 【哭哭哭】附近商户中需要用到的GEO功能只在Redis 6.2以上版本生效 如果用的是老版本&#xff0c;美食/KTV的主页能正常返回&#xff0c;但无法显示内容 上次好不容易升到了5.0以上版本&#xff0c;现在又用不了了 Redis 6.2的windo…

本地部署deepseek模型步骤

文章目录 0.deepseek简介1.安装ollama软件2.配置合适的deepseek模型3.安装chatbox可视化 0.deepseek简介 DeepSeek 是一家专注于人工智能技术研发的公司&#xff0c;致力于打造高性能、低成本的 AI 模型&#xff0c;其目标是让 AI 技术更加普惠&#xff0c;让更多人能够用上强…

[论文总结] 深度学习在农业领域应用论文笔记14

当下&#xff0c;深度学习在农业领域的研究热度持续攀升&#xff0c;相关论文发表量呈现出迅猛增长的态势。但繁荣背后&#xff0c;质量却不尽人意。相当一部分论文内容空洞无物&#xff0c;缺乏能够落地转化的实际价值&#xff0c;“凑数” 的痕迹十分明显。在农业信息化领域的…

快速分析LabVIEW主要特征进行判断

在LabVIEW中&#xff0c;快速分析程序特征进行判断是提升开发效率和减少调试时间的重要技巧。本文将介绍如何高效地识别和分析程序的关键特征&#xff0c;从而帮助开发者在编写和优化程序时做出及时的判断&#xff0c;避免不必要的错误。 ​ 数据流和并行性分析 LabVIEW的图形…

展示统计信息收集情况

看看最近是否收集失败 SET LINES 200 PAGES 0 SET LONG 100000 longc 100000 COLUMN REPORT FORMAT A200VARIABLE stat_report CLOB; BEGIN:stat_report : DBMS_STATS.REPORT_STATS_OPERATIONS (since > SYSDATE-3 , until > SYSDATE , detail_lev…

STM32 TIM输入捕获 测量频率

输入捕获简介&#xff1a; IC&#xff08;Input Capture&#xff09;输入捕获 输入捕获模式下&#xff0c;当通道输入引脚出现指定电平跳变时&#xff0c;当前CNT的值将被锁存到CCR中&#xff0c;可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数 每个高级定时器…

如何将 Windows 上的文件传递到 Mac 上

文章目录 效果需求Windows 上设置共享磁盘【可选】新建一个带有密码的账户查看 Windows 的 IP 地址Mac 上链接 Windows 共享的磁盘 效果 需求 Windows 上有一个有密码的账户 Windows 上设置共享磁盘 windows 这边需要用 Administrator 权限的账号&#xff0c;把要共享的磁盘设…

NLP模型大对比:Transformer > RNN > n-gram

结论 Transformer 大于 RNN 大于 传统的n-gram n-gram VS Transformer 我们可以用一个 图书馆查询 的类比来解释它们的差异&#xff1a; 一、核心差异对比 维度n-gram 模型Transformer工作方式固定窗口的"近视观察员"全局关联的"侦探"依赖距离只能看前…

ODP(OBProxy)路由初探

OBProxy路由策略 Primary Zone 路由 官方声明默认情况&#xff0c;会将租户请求发送到租户的 primary zone 所在的机器上&#xff0c;通过 Primary Zone 路由可以尽量发往主副本&#xff0c;方便快速寻找 Leader 副本。另外&#xff0c;设置primary zone 也会在一定成都上减少…

Python NumPy(7):连接数组、分割数组、数组元素的添加与删除

1 连接数组 函数描述concatenate连接沿现有轴的数组序列stack沿着新的轴加入一系列数组。hstack水平堆叠序列中的数组&#xff08;列方向&#xff09;vstack竖直堆叠序列中的数组&#xff08;行方向&#xff09; 1.1 numpy.concatenate numpy.concatenate 函数用于沿指定轴连…

在线课堂小程序设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

生成模型:扩散模型(DDPM, DDIM, 条件生成)

扩散模型的理论较为复杂&#xff0c;论文公式与开源代码都难以理解。现有的教程大多侧重推导公式。为此&#xff0c;本文通过精简代码&#xff08;约300行&#xff09;&#xff0c;从代码运行角度讲解扩散模型。 本文包括扩散模型的3项技术复现&#xff1a; 1.DDPM (Denoising…

DeepSeek大模型技术解析:从架构到应用的全面探索

一、引言 在人工智能领域&#xff0c;大模型的发展日新月异&#xff0c;其中DeepSeek大模型凭借其卓越的性能和广泛的应用场景&#xff0c;迅速成为业界的焦点。本文旨在深入剖析DeepSeek大模型的技术细节&#xff0c;从架构到应用进行全面探索&#xff0c;以期为读者提供一个…

[权限提升] 常见提权的环境介绍

关注这个框架的其他相关笔记&#xff1a;[内网安全] 内网渗透 - 学习手册-CSDN博客 通过前期的渗透测试&#xff0c;我们大概率会拿到目标的一个 Shell&#xff0c;比如 WebShell 或者 MSF Shell 等等&#xff0c;不同的 Shell 对应提权的姿势也不同&#xff0c;比如有的 Shell…

SQL注入漏洞之高阶手法 宽字节注入以及编码解释 以及堆叠注入原理说明

目录 宽字节注入 编码区分 原理 函数 转译符号解释 注意 绕过方式详解 堆叠【Stack】注入攻击 注入语句 宽字节注入 在说宽字节注入之前 我们需要知道编码相关的知识点&#xff0c;这个有助于搞定什么是宽字节注入 分清楚是ascii码是什么宽字节注入代码里面加入了adds…

Spring Boot - 数据库集成05 - 集成MongoDB

Spring Boot集成MongoDB 文章目录 Spring Boot集成MongoDB一&#xff1a;使用前的准备1&#xff1a;依赖导入 & 配置2&#xff1a;实体类创建 二&#xff1a;核心 - MongoRepository三&#xff1a;核心 - MongoTemplate1&#xff1a;集合操作2&#xff1a;文档操作(重点)3&…