C语言之指针进阶篇(2)
目录
函数指针
函数名和&函数名
函数指针的定义
函数指针的使用
函数指针陷阱
代码1
代码2
注意
函数指针数组定义
函数指针数组的使用
指向函数指针数组的指针
书写
终于军训圆满结束了,首先回顾一下指针进阶篇(1)主要是指针&数组的点!
C语言之指针进阶篇(1)_唐棣棣的博客-CSDN博客https://blog.csdn.net/m0_74841364/article/details/132223126?spm=1001.2014.3001.5502今天我们继续更深入的来了解指针!主要是指针&函数&数组的点!
函数指针
在前面我们已经了解过字符指针,数组指针,这里我们将介绍到函数指针!
指针数组——是数组,是存放指针的数组。
数组指针——是指针,指向数组的指针。
字符指针——指向字符的指针。
整型指针——指向整型的指针。
浮点型的指针——指向浮点型的指针。
函数指针——指向函数的指针。
函数名和&函数名
类比数组指针。
数组指针——指向数组的指针——存放的是数组的地址——&数组名就是数组的地址
函数指针——指向函数的指针——存放的是函数的地址——函数地址是否是&函数名呢?
那我们用代码来验证下。
#include<stdio.h>
int Add(int x, int y)
{return x + y;
}
int main()
{//int x = 0;//int y = 0;//scanf("%d %d", x, y);printf("%p\n", &Add);printf("%p\n", Add);//&函数名 就是函数的地址//函数名 也是函数的地址//注意函数名并没有首元素这一说法
}
&函数名和函数名,都是函数的地址。
那它们是否有什么区别和它们的类型是一样的吗?
它们没有区别,知识写法不一样。
它们两个类型是一样的。指向同一个函数,类型是相同的。
整形函数指针类型?
函数指针的定义
如果在程序中定义了一个函数,那么在编译时系统就会为这个函数代码分配一段存储空间,这段存储空间的首地址称为这个函数的地址。而且函数名和&函数名均表示的就是这个地址。既然是地址我们就可以定义一个指针变量来存放,这个指针变量就叫作函数指针变量,简称函数指针。
那该怎样去写函数指针呢?
#include<stdio.h>
int Add(int x, int y)
{return x + y;
}
int main()
{printf("%p\n", &Add);printf("%p\n", Add);int (*p)(int,int) = &Add;//更容易理解和熟悉int (*p)(int x,int y) = &Add;int (*p)(int x,int y) = Add;//写不写x y都可int (*p)(int,int) = Add;
//&和x y 写不写都可
}
这个语句就定义了一个指向函数的指针变量 p。
首先它是一个指针变量,所以要有一个“*”,即(*p);
其次前面的 int 表示这个指针变量可以指向返回值类型为 int 型的函数;
后面括号中的两个 int 表示这个指针变量可以指向有两个参数且都是 int 型的函数。
所以合起来这个语句的意思就是:
定义了一个指针变量 p,该指针变量可以指向返回值类型为 int 型,且有两个整型参数的函数。
p 的类型为 int(*)(int,int)。
int (*p) (int, int);
函数返回值类型 (* 指针变量名) (函数参数列表);
定义了一个指针变量 p,该指针变量可以指向返回值类型为 int 型,且有两个整型参数的函数。p 的类型为 int(*)(int,int)。
p就是函数指针变量。
那如果写成int* p(int,int);?
*和int 结合 int* 变成了函数声明了。
函数指针的使用
函数指针的使用最长应用在转移表和回调函数 ,那我们在接下来的文章都会讲到。
#include<stdio.h>
int Add(int x, int y)
{return x + y;
}
int main()
{printf("%p\n", &Add);printf("%p\n", Add);int (*p)(int,int) = &Add;int ret=(*p)(3, 5);//解引用找到函数int ret = (********p)(3, 5);//*是个摆设,写不写都可int ret = Add(3, 5);//直接调用Add函数就是用Add函数的地址int ret = p(3, 5);//这里也可以直接使用地址printf("%d", ret);
}
我们有以上三种写法去调用函数 Add,但是我们不可以乱写哦!
int ret=* p(3, 5);
函数指针陷阱
阅读两段有趣的代码!
我们改怎样去理解这两端代码呢?
代码1
(*(void (*)())0)();
//函数调用
图错误待修改
- 在调用 0地址处的函数,这个函数没有参数,返回类型是void
- 把0从int类型强制转化成函数指针类型,指向了0处的地址处的函数
代码2
void (*signal(int , void(*)(int)))(int);
//函数声明
图错误待修改
- 这个代码是一次函数声明,声明的是signal函数
- signal函数有两个参数,一个是int类型,一个是函数指针类型,该类型是void (*)(int)
- 函数指针类型 该函数指针指向的函数,参数是int, 返回类型是void
- signal函数的返回类型也是函数指针类型,该类型是void (*) (int)
- 函数指针类型 该函数指针指向的函数,参数是int, 返回类型是void
代码2太复杂了,那能不能简化代码2???当然可以。
void (* signal(int, void(*)(int)))(int);
//void(*)(int) signal(int void(*)(int));❌
//重定义
typedef void(*pfun_t)(int);
pfun_t signal(int pfun_t);
注 :推荐《C陷阱和缺陷》
注意
- 函数指针变量&函数指针&函数指针类型
- 函数指针类型 修饰一个 函数指针变量(可以是函数等 / 也可以没有/或者 将其他类型强制转化成函数指针类型) 意味着则该函数指针指向一个 返回类型是,参数是的函数
- 函数指针定义
int(*p)(int,int)=Add;
- 函数指针调用
(*p)(3,5); p(3,5); (*p)(); p();//不传参数
- 函数指针声明
void (* signal(int,int))(int);
- 函数指针类型和函数指针变量的写法
int(*p)(int,int); void(*p)(int);
函数指针数组定义
char * arr[5]字符指针数组——数组——存放的是字符指针
int * arr[5]整形指针数组——数组——存放的是整形指针
int(*p[5])(int,int) void(*p[5])(int,char)等等
函数指针数组——数组——存放的是函数指针(函数的地址)
把函数的地址存到一个数组中,那这个数组就叫函数指针数组,那函数指针的数组如何定义呢?
int (*parr1[10]])();
int *parr2[10]();
int (*)() parr3[10];
答案是:parr1 parr1 先和 [] 结合,说明parr1是数组。
数组的内容是什么呢? 是 int (*)() 类型的函数指针。
#include<stdio.h>
int Add(int x, int y)
{return x + y;
}
int Sub(int x, int y)
{return x - y;
}
int main()
{int(*p1)(int, int) = &Add;int(*p1)(int, int) = ⋐//函数指针数组中存放的类型相同的多个元素int(*p[])(int, int) = { &Add,&Sub };//p是函数指针数组_存放函数指针的数组//均是返回类型为int,函数参数是int,int类型
}
函数指针数组的使用
函数指针数组的用途:转移表。
使用条件:函数类型/函数参数类型必须一摸一样
#define _CRT_SECURE_NO_WARNINGS 1
//计算器
#include<stdio.h>
void meau()
{printf("**************************\n");printf("** 1.add 2.sub ****\n");printf("** 3.mul 4.div ****\n");printf("** 0.exit *****\n");printf("**************************\n");
}
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 Div(int x, int y)
{return x / y;
}
int main()
{int input = 0;int x = 0;int y = 0;int ret = 0;do{meau();printf("请选择>");scanf("%d", &input);switch (input){case 1:printf("请输入2个操作数:");scanf("%d %d", &x, &y);ret = Add(x, y);printf("ret=%d\n", ret);break;case 2:printf("请输入2个操作数:");scanf("%d %d", &x, &y);ret = Sub(x, y);printf("ret=%d\n", ret);break;case 3:printf("请输入2个操作数:");scanf("%d %d", &x, &y);ret = Mul(x, y);printf("ret=%d\n", ret);break;case 4:printf("请输入2个操作数:");scanf("%d %d", &x, &y);ret = Div(x, y);printf("ret=%d\n", ret);break;case 0:printf("退出游戏");break;default:printf("选择错误,重新选择\n");break;}} while (input);return 0;
}
能不能让代码变得简单一点?
//简化后
#include<stdio.h>
void meau()
{printf("**************************\n");printf("** 1.add 2.sub ****\n");printf("** 3.mul 4.div ****\n");printf("** 0.exit *****\n");printf("**************************\n");
}
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 Div(int x, int y)
{return x / y;
}
int main()
{int input = 0;int x = 0;int y = 0;int ret = 0;//用函数指针数组//do{meau();printf("请选择>\n");scanf("%d", &input);int(*p[])(int, int) = { NULL,&Add,&Sub,&Mul,&Div };//0 1 2 3 4if (input == 0)printf("退出游戏\n");else if (input > 0 && input <= 4){printf("请输入两个操作数:\n");scanf("%d %d", &x, &y);ret = (*p[input])(x, y);printf("ret=%d\n", ret);// ret = p[input](x, y);//用函数指针数组的下标找到指向的函数}else//其他printf("选择错误,请重新选择!\n");} while (input);return 0;
}
当然出了使用函数指针数组去更高效的使用计算器,下章我们将使用回调函数去高效优化计算器!
指向函数指针数组的指针
指向函数指针数组的指针是一个 指针 指针指向一个 数组 ,数组的元素都是 函数指针 。
指向整型指针数组的指针
#include<stdio.h>
int main()
{int a = 0;int b = 0;int c = 0;int* arr[] = { &a,&b,&c };//整形指针数组int* (*p)[3] = &arr;//p是指针,是指向整形指针数组的指针return 0;
}
函数指针数组的指针
#include<stdio.h>
int main()
{int(*arr[5])(int, int) = { NULL,&Add,&Sub,&Mul,&Div };p = &arr;//存放函数指针数组的指针int(*(*p)[5])(int, int) = &arr;return 0;
}
书写
无论是函数指针&函数指针数组&函数指针数组的指针等等,可以一直延申下去!
我们在书写变量是,首先将变量p写出来,在添加其类型。
也可以从简单的函数指针的基础上修改!
✔✔✔✔✔最后,感谢大家的阅读,若有错误和不足,欢迎指正!最近的心情多做事少说话。
代码------→【gitee:https://gitee.com/TSQXG】
联系------→【邮箱:2784139418@qq.com】
相关文章:
C语言之指针进阶篇(2)
目录 函数指针 函数名和&函数名 函数指针的定义 函数指针的使用 函数指针陷阱 代码1 代码2 注意 函数指针数组定义 函数指针数组的使用 指向函数指针数组的指针 书写 终于军训圆满结束了,首先回顾一下指针进阶篇(1)主要是…...
C++ 进制转化入门知识(1)
一、什么是进制 进制是一种用来表示数值的系统或方法,它是基于一个特定的基数来工作的。在我们常见的几种进制中,有: 1. **二进制(基数 2)**: 二进制只用两个数字:0和1。这是计算机内部使用…...
【React】React学习:从初级到高级(四)
React学习[四] 4 应急方案4.1 使用ref引用值4.1.1 给组件添加ref4.1.2 ref和state的不同之处4.1.3 何时使用ref 4.2 使用ref操作DOM4.2.1 获取指向节点的ref4.2.3 使用 ref 回调管理 ref 列表4.2.4 访问另一个组件的DOM节点4.2.5 用 flushSync 同步更新 state 4.3 使用Effect同…...
微信小程序登录问题(思路简略笔记)
配置问题 这是小程序登录问题,必要的两个配置。 流程思路 1. 微信小程序端,会返回一个code。 2. 查看需要返回给微信小程序端的数据。 3. 既然需要返回三个数据,先看openid如何拿到 WX-Login https://api.weixin.qq.com/sns/jscode2ses…...
Go 锁扩展
文章目录 TryLock统计 goroutine数量读写锁读锁写锁常见死锁情况写锁重入写锁中调用读锁循环依赖 TryLock 源码中自带的(我的go是 1.20版本)TryLock 会尝试获取锁,如果获取不到返回false,并不会进行休眠阻塞(和 Lock的主要区别) func (m *Mutex) TryLo…...
Docker的简介及安装
[shouce]http://shouce.jb51.net/docker_practice/栾一峰菜鸟教程参考文献 1 环境配置的难题 软件开发最大的麻烦事之一,就是环境配置。用户计算机的环境都不相同,你怎么知道自家的软件,能在那些机器跑起来? 用户必须保证两件事…...
安卓核心板的不同核心规格及架构介绍
安卓核心板是将核心功能封装的一块电子主板,集成芯片、存储器和功放器件等,并提供标准接口的芯片。 其特点: ● 能跑 Android 等操作系统 强大的功能及丰富的接口 支持 LCD/TP,Audio,Camera,Video&#…...
flume1.11.0安装部署
1、准备安装包apache-flume-1.11.0-bin.tar.gz; 上传; 2、安装flume-1.11.0; 解压; tar -zxvf apache-flume-1.11.0-bin.tar.gz -C /opt/server 进入conf目录,修改flume-env.sh,配置JAVA_HOME;…...
通过wordpress 自定义主题的额外CSS删除指定区块
最近用wordpress建站,想要删除指定区块,发现相关的教程蛮少的,作为小白的我搜了相关教程,好像没找到,只能自己慢慢摸索了,看了很多,终于尝试实现了,特记录下,免得自己忘了…...
Rokid Jungle--Max pro
介绍和功能开发 YodaOS-Master操作系统:以交换计算为核心,实现单目SLAM空间交互,具有高精度、实时性和稳定性。发布UXR2.0SDK,为构建空间内容提供丰富的开发套件 多模态交互 算法原子化 多种开发工具协同 多生态支持 骁龙XR2…...
【LeetCode算法系列题解】第61~65题
CONTENTS LeetCode 61. 旋转链表(中等)LeetCode 62. 不同路径(中等)LeetCode 63. 不同路径 II(中等)LeetCode 64. 最小路径和(中等)LeetCode 65. 有效数字(困难ÿ…...
MATLAB中fillmissing函数用法
目录 语法 说明 示例 包含 NaN 值的向量 由 NaN 值组成的矩阵 插入缺失数据 使用移动中位数方法 使用自定义填充方法 包含缺失端点的矩阵 包含多个数据类型的表 fillmissing函数的功能是填充缺失的条目。 语法 F fillmissing(A,constant,v) F fillmissing(A,meth…...
电脑同时连接有线和无线网络怎么设置网络的优先级
电脑同时连接有线和无线网络怎么设置网络的优先级: 我们知道在 笔记本电脑系统 中,可以通过有线或无线网络进行联网。如果电脑在有线网络和无线网络同时存在的情况,应该怎么设置有线网络优先连接呢?对此我们提供下面的方法可以让电脑在有Wi…...
el-form表单动态校验(场景: 输入框根据单选项来动态校验表单 没有选中的选项就不用校验)
el-form表单动态校验 el-form常规校验方式: // 结构部分 <el-form ref"form" :model"form" :rules"rules"><el-form-item label"活动名称: " prop"name" required><el-input v-model"form.name" /…...
Java 数据结构与算法应该如何学习?
学习数据结构是计算机科学和软件工程领域中的重要基础知识之一。掌握数据结构对于编写高效、可扩展和可维护的代码至关重要。 1、掌握基本概念 首先,你需要掌握数据结构的基本概念。了解不同类型的数据结构,如数组、链表、栈、队列、树、图等ÿ…...
力扣(LeetCode)算法_C++——有效的数独
请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。 数字 1-9 在每一行只能出现一次。 数字 1-9 在每一列只能出现一次。 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图) …...
制造企业如何优化物料控制?
导 读 ( 文/ 2127 ) 物料控制是指对制造过程中所涉及的物料流动和库存进行有效管理和控制的过程。它包括物料需求计划、供应商管理、物料采购、物料接收和入库、物料库存管理以及物料发放和使用等关键环节。通过精确的物料需求计划和库存管理,物料控制可以确保物料供…...
《Go语言在微服务中的崛起:为什么Go是下一个后端之星?》
🌷🍁 博主猫头虎🐅🐾 带您进入 Golang 语言的新世界✨✨🍁 🦄 博客首页——🐅🐾猫头虎的博客🎐 🐳 《面试题大全专栏》 🦕 文章图文并茂…...
因为axios请求后端,接收不到token的问引出的问题
vue axios请求后端接受不到token的问题。 相关概念 什么是跨域? 跨域指的是在浏览器环境下,当发起请求的域(或者网站)与请求的资源所在的域之间存在协议、主机或端口中的任何一个条件不同的情况。换句话说,只要协议、…...
Stable Diffusion 免费升级 SDXL 1.0,哪些新特性值得关注?体验如何?5 分钟带你体验!
一、引言 7 月 26 日,Stability AI 发布了 SDXL 1.0,号称目前为止,最厉害的开放式图像生成大模型。 它到底有没有网上说的那么炸裂?真的已经实现了像 midjourney 一样 靠嘴出图 的功能吗?相对于之前的版本,…...
【广州华锐互动】煤矿设备AR远程巡检系统实现对井下作业的远程监控和管理
煤矿井下作业环境复杂,安全隐患较多。传统的巡检方式存在诸多弊端,如巡检人员难以全面了解井下情况,巡检效率低下,安全隐患难以及时发现和整改等。为了解决这些问题,提高煤矿安全生产水平,越来越多的企业开…...
C语言与Java语言传输数据 需要转位
在Java语言中,可以通过将整数反转并修改字节顺序来实现低位转高位的转换。下面是一个示例代码,可以将一个整数从低位转高位: public static int toHH(int n) {byte[] bytes ByteBuffer.allocate(4).putInt(n).array();for (int i 0; i <…...
Framework开发——系统默认语言修改
Android 系统原版默认的语言为英文,但是对于中国大陆 Android 产品厂商来说,我们定制系统可能需要用户一开机就是简体中文。所以把 Android 系统出厂设置为简体中文对于 Android 系统产品化非常重要,我们可以通过修改系统属性来达到默认语言的作用。本文主要是在 Android 11…...
浅谈原型链
一.在掌握原型链之前首先要了解这三点 1.每个函数都有prototype这个属性我们称为原型对象 2.每个对象都有__proto__这个属性 3.对象的__proto__可以访问原型对象上的方法和变量,如果访问不了,就会向上进行查找,直到找不到为止,会出现报错的情况l。 二.例子 1.代码: let arr …...
合宙Air724UG LuatOS-Air LVGL API控件-截屏(Screenshots)
截屏(Screenshots) 分 享导出pdf 截屏功能,core版本号要>3211 示例代码 -- 创建图片控件img lvgl.img_create(lvgl.scr_act(), nil)-- 设置图片显示的图像lvgl.img_set_src(img, "/lua/test.png")-- 图片居中lvgl.obj_align(…...
【系统设计系列】 负载均衡和反向代理
系统设计系列初衷 System Design Primer: 英文文档 GitHub - donnemartin/system-design-primer: Learn how to design large-scale systems. Prep for the system design interview. Includes Anki flashcards. 中文版: https://github.com/donnemart…...
Halcon实现3维点云平面拟合
Halcon实现3维点云平面拟合 function main()WindowHandle open_window()ObjectModel3D load_3D_model("1.om3")ObjectModel3DSelected remove_noise(ObjectModel3D)[X, Y, Z] extract_coordinates(ObjectModel3DSelected)[NX, NY, NZ, C] fit_plane(X, Y, Z)vi…...
安全学习DAY23_CookieSessionToken
文章目录 Cookie和Session的区别Token的作用 Cookie和Session的区别 Cookie和Session都是用来在Web应用程序中跟踪用户状态的机制 1、存储位置不同: Cookie是存储在客户端(浏览器)上的,而Session是存储在服务器端的。 2、安全…...
C++ map clear内存泄漏问题
map值存的是指针 map自带的clear()函数会清空map里存储的所有内容,但如果map值存储的是指针,则里面的值不会被清空,会造成内存泄漏,所以值为指针的map必须用迭代器清空。 使用erase迭代删除 迭代器删除值为指针的map,…...
【鲁棒电力系统状态估计】基于投影统计的电力系统状态估计的鲁棒GM估计器(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
多语言网站怎么实现的/怎么建公司网站
这节我们看看“基金行情”表格中的细节,比如以不同颜色显示涨或跌;以横线显示没有值的数据等。 我们的表格是要体现基金的走势的,和股市一样,红色表示上涨,绿色表示下跌等,效果如 这个使用我们在“客户管理…...
做电子政务 网站/品牌网站建设方案
导入MySQL测试数据库employee 报错 下载地址:https://launchpad.net/test-db/ 上传解压: [root001 ~]# tar xf employees_db-full-1.0.6.tar.bz2 [root001 ~]# cd employees_db 使用mysql命令行工具,导入建库建表语句和数据 employee.s…...
电脑网站适应手机如何做/网页制作作业100例
2019独角兽企业重金招聘Python工程师标准>>> 对接外部的一个接口时,发现一个鬼畜的问题,一直提示缺少某个参数,同样的url,通过curl命令访问ok,但是改成RestTemplate请求就不行;因为提供接口的是…...
建设银行网站入口/漯河网站推广公司
作者:匿名用户 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 转帖-[官解]Windows上Python2和3如何兼容 想学习Python3,但是暂时又离不开Python2。在Windows上如何让它们共存呢? 目…...
php开发系统网站建设/东营seo整站优化
一、工作中因为要使用到Tomcat集群部署,此时就涉及到了Session共享问题,主要有三种解决方案: 1、使用数据库来存储Session 2、使用Cookie来存储Session 3、使用Redis来存储Sesssion 二、本文中主要讲一下第3种方案,也就是使用Redi…...
做评选活动的网站/淘宝关键词排名优化技巧
mysql登录密码忘记,其实解决办法很简单,只需要在mysql的主配置文件my.cnf里添加一行“跳过授权表”的参数选择即可!在my.cnf中添加下面一行:[roottest-huanqiu ~]# vim /etc/my.cnf //在[mysqld]区域里添加........s…...