尝试说透C语言指针

news/2024/7/24 12:10:34 标签: c语言, 指针, void, 指针作为容器

前言

不久以前尝试总结过《尝试说透C语言指针》的底稿,但觉得还是写的太复杂了,遂就放弃发布出去。
最近遇到一个事情,觉得void *类型是组织文字的一个比较好的抓手和切入点,以及增补有助理解的图表,就再次有兴趣将其共享出来:)

基本思想

在阅读严蔚敏经典的《数据结构》一书中,有句特别话,引起了我的重点关注,“对于递归,切记想的太深、太远”,我想这句话对于理解指针也是非常适用的。

最简指针形式

基础

任何变量均有地址

无论其是多少级的指针变量,其存储value的语义都是存储内存中的地址信息

无论其是多少级的指针变量,解引用此指针变量意味着从其存储的内存地址开始读写,且按照指针解引用的目标类型操作(也就是减少一级的类型),目标类型主要限定为读写多少个字节信息的内容。

图解指针

在这里插入图片描述

多级指针

Level说明
Type var零级,Type var变量
Type *Ptr一级,解引用获得Type var变量
Type **Ptr2二级,解引用获得Type *Ptr变量
Type ***Ptr3三级,解引用获得Type **Ptr2变量
貌似可以很多级,更难理解了;理解的金钥匙在于指针指向地址是否存在上一级指针类型变量?

图解多级指针

在这里插入图片描述

凶险的指针解引用

场景异常说明
悬空野指针读取的位置悬空就出现非法访问
按照某错误类型或约定类型读取过多的字节信息读取越界的非法访问

void_39">金钥匙void指针

指针作为存储内存地址变量,通常为机器字长度的字节信息,以利于能够存储内存中每个字节的地址信息,所以,指针类型相互赋值,可以没有任何字节信息损失,其sizeof都是同样大小的。

例如,作为万型void *,你可以将各类指针类型转化为void *,也可以将void *按照约定转化为对应类型。

同时,void *经常作为API接口的参数,是因为其不单可以作为某类型的万型指针,还可以变通使用为存储字节信息的容器,例如,整型等。

场景说明
int i ; void* pv = &i; int* pi = (int*)pv指针类型互转
void* pv = (void*)generic_var;作为容器存储变量的值

字节信息容器

typedef struct tagT_KeyInfo 
{
  uint8_t  bType;
  uint16_t wLen;
  union
   {
     uint8_t   data[5];
     uint16_t  wData;
     uint32_t  dwData;
   };
} __attribute__((packed)) T_KeyInfo;

int f(void *arg)
{
  //arg中存储keyInfo信息,所以,按照约定,用求地址运算得到T_KeyInfo的指针,然后解引用
  T_KeyInfo tKeyInfo = *(T_KeyInfo*)&arg;
  
  printf("Passed arg info: bType: %u, wLen: %u, wData: %u\n", tKeyInfo.bType, tKeyInfo.wLen, tKeyInfo.wData);
  
  return 0;
}

int main(int argc, char* argv[])
{
  printf("Hello world !\n");

  T_KeyInfo tKeyInfo = {};
  printf("Cannot convert to a pointer type from struct type!\n");
  //void* p3 = (void*)tKeyInfo;
   
  tKeyInfo.bType = 100;
  tKeyInfo.wLen  = sizeof(uint16_t);
  tKeyInfo.wData = 60000;
  
  /*
   * 指针作为字节容器,可以将机器字长度信息传入
   * 用求地址运算得到某类型的地址,如将其类型转化为void**,则解引用后就可以按照同类型操作,
   * 将字节信息装载到void*中
   */
  void* arg = *(void**)&tKeyInfo; 
  f(arg);
  
  printf("Exit from program !\n");
  return 0;
}

图解指针作为字节容器

在这里插入图片描述

void_105">void*指针作为信息容器为什么称其为精华

// assert(sizeof(VarType) == sizeof(void*))

 void* arg      = *(void\*\*)&var;
 
 //反向
 VarType var    = *(VarType*)&arg

体现C语言的语言特性,在很低硬件层次上可以根据内存地址读写内存,而且读写的语义随类型而变!

指针所指向的内存,如果真正存储了目标,则无惧各种指针操作了 :)


http://www.niftyadmin.cn/n/198365.html

相关文章

Oracle Flex ASM

Oracle Flex ASM 允许 Oracle ASM 实例运行在与数据库服务器分离的物理服务器上。通过这种部署,更大的 Oracle ASM 实例集群可以支持更多的数据库客户端,同时减少整个系统的 Oracle ASM占用空间。当使用 Oracle Flex ASM 时,Oracle ASM 客户端…

prim算法 从连通图中寻找最小生成树的算法 java 记录路径

prim算法 从连通图中寻找最小生成树的算法 2023年4月4日 20:04 稠密图就是边多,点少,点少就用点 边少就用边 点多就用边边多就用点感觉很像dijikstra算法的设计思路 Int visit 记录节点是否记录过 Int dis 记录当前节点到别的节点的最短距离&#x…

ROS实践03 订阅方实现C++

文章目录运行环境:思路:1.1 vscode 环境配置:1)ctrlshiftX 添加扩展插件:2)ctrlshiftB 配置中更换为以下代码1.2 C代码实现1)工作空间创建和编译2)功能包创建和添加依赖3&#xff09…

内存屏障在硬件层面的实现原理以及如何解决各种问题

可见性问题: Store屏障 Load屏障 如果加了Store屏障之后,就会强制性要求你对一个写操作必须阻塞等待到其他的处理器返回invalidate ack之后,对数据加锁,然后修改数据到高速缓存中,必须在写数据之后,强制…

什么是成就动机?如何测试人的成就动机?

什么是成就动机?如何测试人的成就动机? 成就动机是内在动力,激发人才的创造和追求能力,成就动机强的人往往更容易获取学业和职业的成就,在情绪激发理论中,认为成就动机是稳定的人格特征,成就动…

MathType公式使用技巧汇总——Mathtype怎么在word中编辑公式?论文中公式有哪技巧?有哪些注意事项?论文中的公式怎么写?

文章目录1 Mathtype安装2 word 段落间插入公式3 文字间嵌入(内联)公式4 公式修改5 不要使用键盘上的括号等符号5.1 键盘上符号引发的问题5.2 正确的符号使用方法6 常用设置6. 1公式字体大小设置6.2 公式样式设置7 公式标号设置8 MathType怎么设置下一章公…

浏览器是如何确定每一个元素的位置

这节了解:浏览器是如何确定每一个元素的位置 涉及到确定元素位置,那就聊到了我们的排版了,最常见的是正常流排版 正常流排版:正常流是唯一一个文字和盒混排的排版方式,在正常流的文字排版中,多数元素被当…

使用js封装数据类型---队列

一、队列的特点 先进先出,后进后出 二、使用类和数组封装单向队列 // 封装的栈数据类型 class Queue {// 私有属性#items [];// 弹出队列dequeue() {return this.#items.shift();}// 进入队列enqueue(data) {this.#items.push(data);}// 获取队列元素front() {/…