C语言深入理解指针四(17)

embedded/2024/9/23 12:51:40/

文章目录

  • 前言
  • 一、字符指针变量
  • 二、数组指针变量
    • 数组指针变量是什么?
    • 数组指针变量怎么初始化
  • 三、二维数组传参的本质
  • 四、函数指针变量
    • 函数指针变量的创建
    • 函数指针变量的使用
  • 五、两段有趣的代码
    • 代码1
    • 代码2
    • typedef关键字
  • 六、函数指针数组
  • 总结


前言

继续!


一、字符指针变量

  在指针的类型中我们知道有一种指针类型为字符指针char*
一般使用:
在这里插入图片描述
还有一种使用方式如下:
在这里插入图片描述
代码 const char* pstr = “hello bit.”; 特别容易令人误解为把字符串 hello bit. 放到字符指针 pstr 里面,但是本质是把字符串 hello bit. 首字符的地址放到 pstr 中

1.我们可以把字符串想象成一个字符数组,但是这个数组是不能被修改的
2.当常量字符串出现在表达式中的时候,它的值是第一个字符的地址,以下两种写法等价
在这里插入图片描述

有一道关于字符串相关的笔试题,如下:
在这里插入图片描述

请给我你认为的输出

答案是第一个是not,第二个是yes
在这里插入图片描述
我们来思考原因,首先下面那个字符串被const修饰,不会被修改,内容一样,从内存利用率来说,没有必要存多份,只存一份,大家公用即可,而第一个则不然

二、数组指针变量

数组指针变量是什么?

 指针数组:是数组,是存放指针的数组
 整型指针:是指针,指向整型的指针
 数组指针变量:是指针变量,用来存放数组的地址,是能够指向数组的指针变量

为了让你更好地区分,告诉我下面两个分别是什么
在这里插入图片描述
答案是前者是指针数组,后者是数组指针
更准确地说,p1是数组,数组10个元素,每个元素的类型是int*
p2是指针,是指向数组的指针,而所指向的数组有10个元素,每个元素的类型是int

有点绕,你再看看如下:
在这里插入图片描述
通过括号, * 先跟 parr 结合,代表 parr 是一个指针(必须要加括号, [ ] 的优先级大于 * )

数组指针变量怎么初始化

数组指针变量是用来存放数组地址的,那怎么获得数组的地址呢?其实就是我们之前所学的&数组名
在这里插入图片描述

如果要存放,那就得存放到数组指针变量当中,即:
int (*parr)[10] = &arr;

通过调试,我们也能看到 &arr 和 p的类型是完全一致的
在这里插入图片描述

三、二维数组传参的本质

  有了数组指针的理解,我们就能够讲以下二维数组传参的本质了
过去我们有一个二维数组需要传参给一个函数的时候,我们是这样写的:
在这里插入图片描述
  那二维数组可以写成指针吗?可以!
这需要我们再次理解一下二维数组,二维数组可以看做是每个元素是一维数组的数组,也就是二维数组的每个元素是一个一维数组,那么二维数组的首元素就是一行,是个一维数组
在这里插入图片描述
所以,根据数组名是数组首元素的地址这个规划,二维数组的数组名表示的就是第一行的地址,是一维数组的地址,根据上面的例子,第一行的一维数组的类型是int[5],所以第一行的地址的类型就是数组指针类型int (*p)[5],那就意味着二维数组传参本质上也是传递了地址,传递的是第一行在这个一维数组的地址,那么形参也是可以写成指针形式的,如下:
在这里插入图片描述

四、函数指针变量

函数指针变量的创建

  什么是函数指针变量呢?
还是类比,它还是个指针变量,是用来存放函数的地址的变量,未来能通过地址调用函数的
来个测试:
在这里插入图片描述
输出结果如下:
在这里插入图片描述
确实打印出来了地址,所以函数是有地址的,函数名就是函数的地址,当然也可以通过 &函数名 的方式获得函数的地址

跟数组区别的是,函数前面不管加不加取址符 & 都表示函数的地址
int (*pf)(int, int) = &Add; // pf就是函数指针变量
int ret1 = Add(4,9);
int ret2 = (*pf)(4,9); // 调用

函数指针变量的使用

在这里插入图片描述
如上,注意函数指针变量后面的括号加上x,y即(int x, int y)也是可以的

五、两段有趣的代码

代码1

(* ( void ( * )( ) ) 0 )( );
我们发现void(*)()是函数指针类型,而这个类型括号抱起来再跟上0,是强制类型转换,然后再调用
1.把0这个整数值,强制类型转换成一个函数的地址,这个函数没有参数,返回类型是void
2.去调用0地址处的函数!

此段代码出自《C陷阱与缺陷》:在这里插入图片描述

代码2

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

这段代码又是什么意思?哈哈,认真思考,这两句代码是本篇最难的部分了~

先来想signal是啥意思,这里没有传参,也没和 * 混在一起,说明它本身是个函数
而一个函数,参数有了,那么还差返回类型,我们把函数名和参数去掉,最后就发现剩下了void( * )(int)
所以,signal函数的参数有2个,第一个是int类型,第二个是函数指针类型,该指针指向的函数参数是int,返沪类型为void
signal函数的返回类型是这种类型的void(*)(int)函数指针
该指针指向的函数参数是int,返回类型是void

typedef关键字

typedef关键字是用来简化类型名的
比如说定义一个无符号整数num

unsigned int num; // 太麻烦

这时候,我们可以重命名

typedef unsigned int uint;
typedef int* ptr_t;
typedef int(* parr_t)[5]; // 简化指针类型int (*)[5]
注意,要修改数值指针类型和函数指针类型的时候,名字放里面

对于前面的void (* signal(int, void(*)(int) ) )(int);
我们把 void ( * )(int) 重命名一下
typedef void( * pf_t)(int);

所以上述代码可以简化为
pf_t signal(int, pf_t)(int);

六、函数指针数组

  如果我们要设计一个计算器,要求对整型进行四种运算,显然第一想到的是switch…case语句,可这样代码过于冗杂,我们可以尝试把四种运算都放在一个数组里面,这个数组就是函数指针数组
在这里插入图片描述
跟函数指针变量相比,就是在名字后面加上了[ ],我们成功的将函数的地址放进数组里,这意味着我们可以更加高效的管理函数了!


总结

  回调函数预告,我保证下一章你会感慨函数调用的奇妙!


http://www.ppmy.cn/embedded/110276.html

相关文章

pv和pvc

pv和pvc pv: Persistent volume 是k8s虚拟化的存储资源,实际上就是存储,例如本地的硬盘,网络文件系统(nfs) lvm RAID oss(ceph) 云存储。 pvc: Persistent volume claim 用户对…

如何让Google收录我的网站?

其实仅仅只是收录,只要在GSC提交网址,等个两三天,一般就能收录,但收录是否会掉,这篇内容收录了是否有展现,排名,就是另外一个课题了,如果不收录,除了说明你的网站有问题&…

基于YOLOv8的遥感光伏板检测系统

基于YOLOv8的遥感光伏板检测系统 (价格85) 包含 [光伏板] 1个类 通过PYQT构建UI界面,包含图片检测,视频检测,摄像头实时检测。 (该系统可以根据数据训练出的yolov8的权重文件,运用在其他检测系统上,如火…

JVM工作过程

将JVM工作过程粗略分为5个阶段,包括加载阶段、链接阶段、初始化阶段、执行阶段、回收阶段 其中, (1)加载阶段、链接阶段的解析部分主要由类加载器完成 (2)初始化阶段是由JVM的类加载机制在类加载过程的最后…

什么是嵌入式?行业前景如何?

目录 什么是嵌入式? 主要特点 常见应用场景 1. 工业自动化 2. 交通运输 3. 智能家居 4. 消费电子 5. 医疗设备 6. 航空航天 7. 物联网(IoT) 8. 能源管理 行业前景如何? 市场需求强劲 物联网(IoT)的爆发 汽车…

【深度学习】磁盘的转速影响

深度学习,确切的说是计算机视觉,对磁盘的转速是有要求的。 5400转,7200转,转速要大一点。有的是能调转速的,有的不能。 这次我买的这个服务器调不了。 (base) justinjustin-System-Product-Name:~$ sudo hdparm -I …

科大讯飞 鉴权教程

<?php// 定义HmacWithShaTobase64函数&#xff0c;用于生成HMAC-SHA256签名并进行base64编码 function HmacWithShaTobase64($algo, $data, $key) {return base64_encode(hash_hmac(sha256, $data, $key, true)); }// 模拟assembleAuthUrl函数的功能 function assembleAuth…

嵌入式学习路线+嵌入式校招建议 嵌入式学习面试规划

随着物联网、人工智能以及5G等技术的迅猛发展&#xff0c;嵌入式系统的需求逐渐增多。作为毕业生&#xff0c;如何制定一个合理的学习路线&#xff0c;以确保在找工作、参加校招时有足够的竞争力&#xff0c;是非常重要的。我会为你提供一个更加详细、系统的学习路线建议&#…