C语言-------指针进阶(2)
1.指针数组
指针数组表较简单,类比整型数组,字符数组,整型数组里面的元素都是整型变量,字符数组里面
的元素是字符类型,那么指针数组就是数组里面的每个元素都是指针类型,例如int*arr[5]就是一个
指针数组,数组里面的元素都是int*的指针类型;
2.数组指针
数组指针是什么,如何使用,我们回忆一下二维数组传参,我们知道一维数组的传参,例test函数
test(arr)参数arr是数组名,就是数组首个元素的地址,我们也可以使用数组接受,也可以使用指针
指向首个元素的地址,通过指针的移动打印数组的元素;
同理,二维数组传参,例如arr[3][5],传递参数test(arr),arr是二维数组的名字,但是不是设个元素的
地址,而是首行元素的地址,这个时候如果想要使用指针接受,这个指针就应该是数组指针,指向
的是一个数组,还是拿这个3行5列数组举例,对于二维数组我们可以这样理解,把二维数组理解成
3个一维数组,实际上传递进去的是第一行以为数组的地址,有5个元素,我们使用数组指针
int(*p)[5]进行接收,这个数组指针表示指向5个元素,每个元素的类型是int类型,数组指针的名字
是p指针,指针类型int(*)[5],指针的类型决定了对指针进行加一操作会跳过几个字节,如果是普通的
整形指针数组,加一就跳过4个字节,但是这里的p指针的类型是int(*)p,所以加一会跳过5个元素,
也就是20字节。
3.函数指针变量
我们知道数组名表示 数组首个元素的地址,函数名同样表示函数的地址,取地址数组名表示整个
数组的地址,但是取地址函数名仍然是函数的地址,和直接的函数名没有区别
图片里面int (*p)(int,int)就是定义函数指针,这个函数指针的参数有2个,都是int类型
这个函数的返回类型是int类型,实际上在进行调用的时候,加上星号只是为了表示他是函数指针
加上2个或者多个星号都不影响使用,不加星号都是可以的,通过打印结果也可以知道,
看似,即使没有函数指针,我们也可以对函数进行使用,实际上后续函数指针会发挥巨大作用
4.二段有趣的代码分析
1 (*(void (*)())0)();
这个里面的void(*)()是函数指针类型,放在括号里面就是进行强制类型转换,把0转换成函数指针类
型,0是个地址,这里的星号同上,是可以省略的,调用0地址处的这个函数,(这里面的0仅仅是一
个地址)这个函数指针没有参数,传递的参数也是空的,如果要调用100地址处的函数,就是
100,总言之,这是一次函数的调用;
2.void (*signal(int , void(*)(int)))(int);
这个里面的void(*)(int)也是函数指针变量,参数int类型,返回void类型,signal是一个函数,函
数的参数是int类型,和函数指针类型,去掉后是void(*)(int)还是一个函数指针类型,也就是这个函
数的返回值是函数指针类型,函数的声明只需要高数参数的类型,可以不写名字,可能初学者会问
可不可以写为void(*)(int) signal(int,void(*)(int),或许这样写更加清楚,但是编译器不支持;实质上
这个是函数的声明;
5.typedef关键字的使用
上面的这个例子,对于比较长的数据类型或者指针类型,名字我们可以进行简化,这个时候就有了
typedef关键字
typedef unsigned int ptr就是把unsigned int这个比较长的类型用ptr代替
我们定义unsigned int a=10;就可以直接写为ptr a=10,使得原来复杂代码简单化,就是重新起名字
还例如指针类型也可以进行简化,int*类型也可以这样简化,typedef int* asd,就是简化后名字asd
int(*p)[5]是数组指针,类型int(*)[5],也可以重新命名,不是int(*)[5] ptr,需要写为typedef int(*ptr)[5]
ptr也是一种类型了,平时的int(*p2)[5]=&arr(这里的p2就是指针变量)就可以写为ptr p2=&arr,
函数指针类型重命名,原来的 void (*pf)(int)函数指针,typedef void(*)(int) ptr;以后定义就可以
写作ptr p2=&add,这样定义函数指针类型;
同样使用ptr重命名函数指针,void (*signal(int , void(*)(int)))(int);就可以简化为
ptr signal(int,ptr),变得更加简单,简洁高效。
typrdef int* ptr;就是关键字重命名;
#define int* PTR就是遇到PTR使用int*替代,ptr a相当于int*a,这样也可以简化;
第一一个变量的时候两者无区别,定义2个时候就有区别
ptr a,b;可以同时定义a,b都是int*类型
PTR a,b;不能同时定义a,b是int*类型,只能定义a ,b还是默认的int 类型;
由此可见,使用重命名的时候,尽量使用typedef,使用#define可能会出现问题。
6,函数指针数组
(1)首先讲一下函数指针数组如何使用:
每一个运算的法则都是函数指针,因为他们的参数,返回类型都是相同的,所以我们可以放到
一个数组里面,这个数组就叫做函数指针数组,循环里面直接调用就可以了;
函数指针数组就是在函数指针名字后面加上元素个数;
(2)接下来讲一下函数指针数组如何使用:以一个计算机的构建为例,这个计算机可以实现
简单的四则运算;下面是自定义函数和主函数的代码
下面的是函数
int add(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 divi(int x, int y)
{return x / y;
}
下面主函数(注意除法的自定义函数不能直接使用div,本人亲测,div和库函数里面的div冲突)
void menu()
{printf("*****************************************\n");printf("**********1.add**************************\n");printf("**********2.sub**************************\n");printf("**********3.mul**************************\n");printf("**********4.divi**************************\n");printf("**********0.exit*************************\n");
}
int main()
{int input = 0;int x = 0;int y = 0;int ret = 0;do {menu();printf("请选择\n");scanf("%d", &input);switch (input){case 1:printf("请输入2个数字\n");scanf("%d %d", &x, &y);ret = add(x, y);printf("%d\n", ret);break;case 2:printf("请输入2个数字\n");scanf("%d %d", &x, &y);ret = sub(x, y);printf("%d\n", ret);break;case 3:printf("请输入2个数字\n");scanf("%d %d", &x, &y);ret = mul(x, y);printf("%d\n", ret);break;case 4:printf("请输入2个数字\n");scanf("%d %d", &x, &y);ret = divi(x, y);printf("%d\n", ret);break;case 0:printf("退出计算器");break;default:printf("请重新选择\n");break;}} while (input);return 0;
}
思考分析简化:
这个是一个普通的计算器,只有加减乘除法则运算;
这样看来,每个case都要重复,显示的有些冗余,这个时候可以使用函数指针数组;
int main()
{int input = 0;int x = 0;int y = 0;int ret = 0;int(*ptr[5])(int,int) = {NULL,add,sub,mul,divi};do{menu();printf("请选择\n");scanf("%d", &input);if (input >= 1 && input <= 4){printf("请输入2个数字\n");scanf("%d %d", &x, &y);ret = ptr[input](x, y);printf("%d\n", ret);}else if (input == 0){printf("退出计算器\n");break;}else{printf("选择错误,重新选择\n");}} while (input);return 0;
}
这个时候,引入数组,里面就是函数,因为要使我们输入的input和数组元素的下标相对应,
所以我们把第一个元素设置为NULL,这样我们选择哪个数字,就可以找到对应函数地址,使用这个
函数,这样函数的下标就是1,2,3,4了;ptr[input]直接找到对应的地址,使用这个函数
而且,如果想要增加法则,只需要增加数组元素就可以了,如果不是用这种数组,就需要
增加case语句,里面的内容还是需要重复,更加复杂,函数指针数组的优势就体现了出来。
相关文章:

C语言-------指针进阶(2)
1.指针数组 指针数组表较简单,类比整型数组,字符数组,整型数组里面的元素都是整型变量,字符数组里面 的元素是字符类型,那么指针数组就是数组里面的每个元素都是指针类型,例如int*arr[5]就是一个 指针数…...
Spring El表达式官方文档学习
文章目录 推荐一、概述1、什么是SpEL2、SpEL能做什么 二、SpEL表达式使用1、文字表达式2、属性, 数组, List, Map,和 索引(1)属性操作(2)数组和List(3)Map 3、内嵌List4、内嵌Map5、构建数组6、调用类的方法…...

RK3568 android11 调试陀螺仪模块 MPU6500
一,MPU6500功能介绍 1.简介 MPU6500是一款由TDK生产的运动/惯性传感器,属于惯性测量设备(IMU)的一种。MPU6500集成了3轴加速度计、3轴陀螺仪和一个板载数字运动处理器(DMP),能够提供6轴的运动…...

【HTML】HTML基础6.1(表格以及常见属性)
目录 表格介绍 表格标签 表格标签的常见属性 案例 知识点总结 表格介绍 在浏览器中,我们经常见到形如 这样的表格形式,一般来说,表格是为了让数据看起来更加清晰,增强数据的可读性 有的程序员也会用表格进行排版 表格标签 &…...

数字电路三宝:锁存器、寄存器和触发器
在数字电路设计中,很多电子工程师经常会用到锁存器、寄存器和触发器,它们各自承担着不同的功能,但共同为数字电路的稳定性和高效性提供了坚强保障,下面将谈谈这三大元件,希望对小伙伴们有所帮助。 1、锁存器࿰…...
VLC相关资源及使用方法
资源 VLC源码: VLC的源码,与VLC Contrib配合使用可以编译相应的库、程序等,如果没有Contrib,可以使用源码下面的contrib文件夹下对应程序自动下载,单独编译,但是速度很慢。 下载地址: 官网&…...

4_相机透镜畸变
理论上讲,是可能定义一种透镜而不引入任何畸变的。然而现实世界没有完美的透镜。这主要是制造上的原因,因为制作一个“球形”透镜比制作一个数学上理想的透镜更容易。而且从机械方面也很难把透镜和成像仪保持平行。下面主要描述两种主要的透镜畸变并为他…...

微信小程序(四十六)登入界面-进阶版
注释很详细,直接上代码 上一篇 此文使用了vant组件库,没有安装配置的可以参考此篇vant组件的安装与配置 新增内容: 1.手机号与验证码格式验证 2.验证码的网络申请和校验 wechat-http模块在好几篇以前已经讲了咋安装的,不记得的友…...

CSP-201712-2-游戏
CSP-201712-2-游戏 解题思路 初始化变量:定义整数变量n和k,分别用来存储小朋友的总数和淘汰的特定数字。然后定义了num(用来记录当前报的数)和peopleIndex(用来记录当前报数的小朋友的索引)。 初始化小朋…...

记录SSM项目集成Spring Security 4.X版本 之 加密验证和记住我功能
目录 前言 一、用户登录密码加密认证 二、记住我功能 前言 本次笔记的记录是接SSM项目集成Spring Security 4.X版本 之 加入DWZ,J-UI框架实现登录和主页菜单显示-CSDN博客https://blog.csdn.net/u011529483/article/details/136255768?spm1001.2014.3001.5502 文章之后补…...

[AutoSar]BSW_Com09 CAN driver 模块FULL(BASIC)CAN、FIFO选择
目录 关键词平台说明一、FULL CAN 和Basic CAN 关键词 嵌入式、C语言、autosar、OS、BSW 平台说明 项目ValueOSautosar OSautosar厂商vector ,芯片厂商TI 英飞凌编程语言C,C编译器HighTec (GCC)autosar版本4.3.1 >>>>>回到总目录<&…...

WPF真入门教程30--顺风物流单据管理系统
1、教程回顾 到现在为止,真入门系列教程已完成了29刺由浅入深地讲解,当然不可能讲到了WPF的所有技能点,但读者看到了wpf的内部各种功能及之间的联系,在此基础上,提供一个完整有效的综合项目,本项目采用的是…...

Elasticsearch:向量相似度计算 - 可笑的速度
作者:Chris Hegarty 任何向量数据库的核心都是距离函数,它确定两个向量的接近程度。 这些距离函数在索引和搜索期间执行多次。 当合并段或在图表中导航最近邻居时,大部分执行时间都花在比较向量的相似性上。 对这些距离函数进行微观优化是值…...
两数相加的问题
题目是:给两个非空的链表,表示两个非负整数。它们每位数都是按照逆序的方式存储,并且每一个节点只能存储一位数字。现在两个数相加,并且以相同的形式返回一个表示和的链表。 首先回顾一下,什么是链表?链表…...
微信小程序的单位
在小程序开发中,rpx是一种相对长度单位,用于在不同设备上实现自适应布局。它是微信小程序特有的单位,表示屏幕宽度的 1/750。 rpx单位的好处在于可以根据设备的屏幕宽度进行自动换算,使得页面在不同设备上保持一致的显示效果。例…...

软考通过率真的低吗?
软考通过率有多少?高项有必要找培训机构吗? 相对来说软考的通过率的确比其他考试要低,因为它的知识点有点杂,专业知识、政策、计算机系统各个方面的知识都需要去掌握。根据以往的数据来说高项(信息系统项目管理师&…...
国际视频编解码标准提案下载地址
H.266 相关提案下载地址:http://phenix.it-sudparis.eu/jvet/ 更新的地址:https://jvet-experts.org/ H.265 提案下载地址:http://phenix.int-evry.fr/jct/ 标准文档下载地址:http://www.itu.int/rec/T-REC-H.265 H.264 提案下载…...

程序员是如何看待“祖传代码”的?
文章目录 每日一句正能量前言祖传代码的历史与文化价值祖传代码的技术挑战与机遇祖传代码与现代开发实践的融合祖传代码的管理与维护策略后记 每日一句正能量 黎明时怀着飞扬的心醒来,致谢爱的又一天,正午时沉醉于爱的狂喜中休憩,黄昏时带着感…...
Python爬虫之爬取并下载哔哩哔哩视频
亲自使用过,太好用了 # 导入requests模块,模拟发送请求 import requests # 导入json import json # 导入re import re# 定义请求头 headers {Accept: */*,Accept-Language: en-US,en;q0.5,User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6…...
python 脚本设置输出颜色
在Python脚本中设置输出颜色,通常可以使用colorama库,它可以在Windows、Linux和macOS等平台上工作。colorama库扩展了Python的标准库,使得在控制台输出彩色文本更加简单。 首先,你需要安装colorama库。如果你还没有安装ÿ…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
day52 ResNet18 CBAM
在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...

安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的
修改bug思路: 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑:async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...
虚拟电厂发展三大趋势:市场化、技术主导、车网互联
市场化:从政策驱动到多元盈利 政策全面赋能 2025年4月,国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》,首次明确虚拟电厂为“独立市场主体”,提出硬性目标:2027年全国调节能力≥2000万千瓦࿰…...