C语言之探秘:访问结构体空指针与结构体空指针的地址的区别(九十三)

news2024/12/23 20:06:03

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!

优质专栏:Audio工程师进阶系列原创干货持续更新中……】🚀
优质专栏:多媒体系统工程师系列原创干货持续更新中……】🚀
优质视频课程:AAOS车载系统+AOSP14系统攻城狮入门实战课原创干货持续更新中……】🚀

人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.

更多原创,欢迎关注:Android系统攻城狮

欢迎关注Android系统攻城狮

🍉🍉🍉文章目录🍉🍉🍉

    • 🌻1.前言
    • 🌻2.C语言之结构体空指针与结构体空指针的地址介绍
    • 🌻3.代码实例
      • 🐓3.1 (frame_t *)0 等同于 frame_t *p = NULL;
      • 🐓3.2 问题一:为什么访问p->f1发生段错误?而&(p->f1)则不会?
      • 🐓3.3 问题二: (frame_t *)0 和 frame_t *p = NULL;区别?
      • 🐓3.4 问题三: 根据打印,发现&(p->f1)打印等于8,正好是f1在frame_t中的偏移,而不是地址,为什么&(p->f1)表示的是f1成员变量在frame_t的偏移,而不是地址?

🌻1.前言

本篇目的:C语言之探秘:访问结构体空指针与结构体空指针的地址的区别

🌻2.C语言之结构体空指针与结构体空指针的地址介绍

  • 在C语言中,结构体(Struct)是一种复合数据类型,它可以包含多个不同类型的数据项。指针(Pointer)是一种特殊的数据类型,用于存储变量地址。空指针(Null Pointer)是一个不指向任何有效内存地址的特殊指针。
  • 当我们谈论结构体空指针与结构体空指针的地址时,我们需要明确两个概念:结构体变量的地址和结构体指针的地址。
    1. 结构体空指针:
  • 结构体空指针是指未经初始化的结构体指针,它不指向任何有效的内存地址。在C语言中,我们可以使用malloc函数或calloc函数为结构体指针分配内存。如果没有分配内存,那么这个结构体指针就是空指针。
struct Person {
    char *name;
    int age;
};
struct Person *p = NULL; // 声明一个结构体指针,并初始化为空指针
  • 在这种情况下,p是一个空指针,它不指向任何有效的内存地址。
    1. 结构体空指针的地址:
  • 结构体空指针的地址是指结构体指针变量在内存中的存储位置。在C语言中,每个变量都有一个唯一的地址。我们可以使用&操作符来获取变量的地址。
struct Person *p;
printf("%p\n", (void*)&p); // 输出结构体指针变量的地址
  • 输出结果将是一个十六进制的地址值,表示p在内存中的位置。
  1. 结构体空指针与结构体空指针地址的区别:
  • 结构体空指针是一个不指向任何有效内存地址的特殊指针,而结构体空指针的地址是指结构体指针变量在内存中的存储位置。这两者是不同的概念,不能混淆。
struct Person *p = NULL; // 空指针
printf("%p\n", (void*)p); // 输出空指针的值,即NULL
printf("%p\n", (void*)&p); // 输出空指针变量的地址
  • 输出结果将是:
(nil)
0x7ff7bfeff8ac
  • 在这里,第一个输出表示空指针的值,即NULL。第二个输出表示空指针变量p在内存中的地址。
  • 在C语言中,结构体空指针与结构体空指针的地址是两个不同的概念。结构体空指针是一个不指向任何有效内存地址的特殊指针,而结构体空指针的地址是指结构体指针变量在内存中的存储位置。理解这两个概念有助于避免在编程过程中出现错误。

🌻3.代码实例

🐓3.1 (frame_t *)0 等同于 frame_t *p = NULL;

#include <stddef.h>
#include <stdio.h>
//#include <stddef.h>

#undef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ({                      \
      const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
      (type *)( (char *)__mptr - offsetof(type,member) );})

typedef struct frame {
  int num;
  char name;
  float f1;
}frame_t;

int main(void)
{
  frame_t fra, *pf;
  fra.num = 1;
  fra.name = 'M';
  fra.f1 = 1.23;

  //v1.0 (frame_t *)0用法
  printf("(frame_t *)0 = %p\n",(frame_t *)0);
  printf("(frame_t*)0->f1 = %p\n",&(((frame_t *)0)->f1));
  printf("(frame_t*)1->f1 = %p\n",&(((frame_t *)1)->f1));
  printf("(frame_t*)2->f1 = %p\n",&(((frame_t *)2)->f1));
  printf("(frame_t*)3->f1 = %p\n",&(((frame_t *)3)->f1));

  //v2.0 frame_t *p = NULL用法.
  frame_t *p = NULL;
  printf("p = %p\n",p);
  //printf("p = %ld\n",p->f1);//段错误
  printf("p = %p\n",&(p->f1));

  //v3.0
  int aa = 1;
  frame_t *q = (frame_t *)&aa;
  printf("q = %p\n",q);
  printf("q = %p\n",&(q->name));
  return 0;
}


打印:
(frame_t )0 = (nil)
(frame_t
)0->f1 = 0x8
(frame_t*)1->f1 = 0x9
(frame_t*)2->f1 = 0xa
(frame_t*)3->f1 = 0xb
p = (nil)
p = 0x8
q = 0x7ffe13c1f4a4
q = 0x7ffe13c1f4a8

计算地址:
(frame_t*)0->f1 = 0x8 + 0 = 0x8 = 8
(frame_t*)1->f1 = 0x8 + 1 = 0x9 = 9
(frame_t*)2->f1 = 0x8 + 2 = 0xa = 10
(frame_t*)3->f1 = 0x8 + 3 = 0xb = 11
结论:
(frame_t*)0:等于指向0指针的偏移量 + 成员变量f1偏移量,等于8.
(frame_t*)0:等于指向1指针的偏移量 + 成员变量f1偏移量,等于9.
(frame_t*)1:等于指向2指针的偏移量 + 成员变量f1偏移量,等于10.
(frame_t*)2:等于指向3指针的偏移量 + 成员变量f1偏移量,等于11.

🐓3.2 问题一:为什么访问p->f1发生段错误?而&(p->f1)则不会?

答:
<1>.p->f1:打印指针 p 中 f1 成员的内容,但 p 是一个空指针,没有指向任何有效的内存。因此,访问 p->f1 会导致段错误。
<2>.&(p->f1) :打印指针 p 中 f1 成员的地址,不会导致段错误,因为它没有尝试访问 f1 的内容。

🐓3.3 问题二: (frame_t *)0 和 frame_t *p = NULL;区别?

<1>.在C语言中,frame_t *p = NULL; 将指针 p 初始化为空指针,意味着 p 指向的是一个特殊的空地址,不指向任何实际的结构体对象.访问 p 所指向的对象时,通常会导致未定义行为,可能会导致程序崩溃。
<2>.而 (frame_t *)0 是一个显式地将一个整数0转换为 frame_t 结构体指针类型的操作。这实际上将该指针设置为一个特定的地址,即空指针地址。
<3>.因此,(frame_t *)0 实际上与 frame_t *p = NULL; 的作用相同,都是将指针设置为空指针。

🐓3.4 问题三: 根据打印,发现&(p->f1)打印等于8,正好是f1在frame_t中的偏移,而不是地址,为什么&(p->f1)表示的是f1成员变量在frame_t的偏移,而不是地址?

答:
<1>.在C语言中,结构体的成员在内存中是连续存储的,因此可以通过计算偏移量来获取结构体成员的地址。
&(p->f1) 中的 & 运算符表示取地址操作,它取的是 f1 成员的地址,而不是简单的偏移量。
<2>.假设 p 指向一个有效的 frame_t 结构体对象,则 &(p->f1) 将返回 f1 成员的地址。
但是,如果 p 是空指针,则 &(p->f1) 仍然会尝试计算 f1 成员的地址,因为这是一个合法的操作,但是实际上不会返回有效的地址,因为它仅仅是一个空指针的偏移量加上 f1 成员在结构体中的偏移量。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端标记语言HTML

HTML&#xff08;HyperText Markup Language&#xff09;是一种用于创建网页的标准标记语言。它是构建和设计网页及应用的基础&#xff0c;通过定义各种元素和属性&#xff0c;HTML使得开发者能够组织和格式化文本、图像、链接等内容。 HTML的基本结构 文档类型声明&#xff0…

Adobe Premiere 2020 下载地址及安装教程

Premiere是一款专业的视频编辑软件&#xff0c;由Adobe Systems开发。它为用户提供了丰富的视频编辑工具和创意效果&#xff0c;可用于电影、电视节目、广告和其他多媒体项目的制作。 Premiere具有直观的用户界面和强大的功能&#xff0c;使得编辑和处理视频变得简单而高效。它…

【AngularJs】前端使用iframe预览pdf文件报错

<iframe style"width: 100%; height: 100%;" src"{{vm.previewUrl}}"></iframe> 出现报错信息&#xff1a;Cant interpolate: {{vm.previewUrl}} 在ctrl文件中信任该文件就可以了 vm.trustUrl $sce.trustAsResourceUrl(vm.previewUrl);//信任…

Python基于卷积神经网络的车牌识别系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

qt5-按字节读取并解析含属性的xml文件

参考&#xff1a; 对XML文件读取和编辑2-QXmlStreamReader读取 - 知乎 https://zhuanlan.zhihu.com/p/358862429 本地环境&#xff1a; win10专业版&#xff0c;64位&#xff0c;Qt 5.12 代码已测试通过。 问题描述 需要按字节读取一个文档&#xff0c;解析其中具有xml格式的…

【C语言回顾】数组

前言1. 数组2. 一维数组2.1 一维数组的创建2.2 一维数组的初始化2.3 一维数组的使用2.3.1 一维数组的下标2.3.2 一维数组的输入和输出 2.4 一维数组在内存中的存储 3. 二维数组3.1 二维数组的创建3.2 二维数组的初始化3.3 二维数组的使用3.3.1 二维数组的下标3.3.2 二维数组的输…

ELK日志收集和备份填坑实战 (滞后8个小时等时区问题)

ES的备份&#xff1a;ES快照备份 根据时间&#xff0c;每天零点在Linux机器crontab来调用api接口实现快照备份&#xff0c;通过快照备份&#xff0c;可以定准恢复到某一天的日志。 现象&#xff1a;&#xff08;坑&#xff1a;但是恢复某一天日志&#xff0c;发现会少8小时的日…

暴力破解密码自动阻断

1 re模块 re 模块是 Python 中用于正则表达式操作的模块。正则表达式&#xff08;Regular Expression&#xff09;是一种强大的文本处理工具&#xff0c;它使用一种特殊的字符序列来表示字符串中的模式&#xff0c;并可以通过模式匹配、查找、替换等操作对文本进行高效处理。 …

【Qt】:对话框(二)

对话框 一.消息对话框&#xff08;QMessageBox&#xff09;1.自己构建2.使用静态函数构建 二.颜色对话框&#xff08;QDialog&#xff09;三.文件对话框&#xff08;QFileDialog&#xff09;四.字体对话框&#xff08;QFontDialog&#xff09;五.输入对话框&#xff08;QInputD…

光场相机建模与畸变校正改进方法

摘要&#xff1a;光场相机作为一种新型的成像系统&#xff0c;可以直接从一次曝光的图像中得到三维信息。为了能够更充分有效地利用光场数据包含的角度和位置信息&#xff0c;完成更加精准的场景深度计算&#xff0c;从而提升光场相机的三维重建的精度&#xff0c;需要实现精确…

PgSQL之WITH Queries/Statement

PostgreSQL WITH 子句 在 PostgreSQL 中&#xff0c;WITH 子句提供了一种编写辅助语句的方法&#xff0c;以便在更大的查询中使用。 WITH 子句有助于将复杂的大型查询分解为更简单的表单&#xff0c;便于阅读。这些语句通常称为通用表表达式&#xff08;Common Table Express…

《Kubernets证书篇:基于Kylin V10+ARM架构CPU修改K8S 1.26.15版本证书时间限制》

一、背景 Kubernetes 默认的证书有效期只有1年&#xff0c;因此需要每年手动更新一次节点上面的证书&#xff0c;特别麻烦而且更新过程中可能会出现问题&#xff0c;因此我们要对 Kubernetes 的 SSL 证书有效期进行修改&#xff0c;这里将证书的时间限制修改为100年。 环境信息…

视频国标学习

总体介绍 GB/T28181协议&#xff0c;全名叫《安全防范视频监控联网系统信息传输、交换、控制技术要求》&#xff0c;是由中国国家标准委员会发布的一种国家级的标准。它主要对视频监控系统的各个方面做了明确的规定&#xff0c;使得不同厂商生产的视频监控设备能够相互连通&am…

JavaScript之Proxy详解

文章的更新路线&#xff1a;JavaScript基础知识-Vue2基础知识-Vue3基础知识-TypeScript基础知识-网络基础知识-浏览器基础知识-项目优化知识-项目实战经验-前端温习题&#xff08;HTML基础知识和CSS基础知识已经更新完毕&#xff09; 正文 Proxy是JavaScript中的一个强大而灵活…

linux 自定义快捷指令(docker

vi /root/.bashrc alias disdocker images alias dpsdocker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}" 保存退出后使用sourece /root/.bashrc 让其立即生效 sourece /root/.bashrc

【C 数据结构】栈

文章目录 【 1. 基本原理 】栈的分类 【 2. 动态链表栈 】2.1 双结构体实现2.1.0 栈的节点设计2.1.1 入栈2.1.2 出栈2.1.3 遍历2.1.4 实例 2.2 单结构体实现2.2.0 栈的节点设计2.2.1 入栈2.2.2 出栈2.2.3 实例 【 3. 顺序栈 】3.1 入栈3.2 出栈3.3 实例 【 1. 基本原理 】 栈&…

牛客网刷题 :BC50 你是天才吗

描述 据说智商140以上者称为天才&#xff0c;KiKi想知道他自己是不是天才&#xff0c;请帮他编程判断。输入一个整数表示一个人的智商&#xff0c;如果大于等于140&#xff0c;则表明他是一个天才&#xff0c;输出“Genius”。 输入描述&#xff1a; 多组输入&#xff0c;每…

【opencv】示例-videocapture_microphone.cpp 使用OpenCV库实现的音频捕获

#include <opencv2/core.hpp> // 包含OpenCV核心功能头文件 #include <opencv2/videoio.hpp> // 包含OpenCV视频输入输出头文件 #include <opencv2/highgui.hpp> // 包含OpenCV高层GUI头文件 #include <iostream> // 包含标准输入输出流头文件using na…

SS3D翻译

SS3D AbstractIntroductionRelated WorkFully-Supervised 3D Object DetectionWeakly/Semi-Supervised 3D Object DetectionSparsely-Supervised 2D Object Detection MethodOverall FrameworkArchitecture of DetectorMissing-Annotated Instance Mining Module 缺失注释实例挖…

leetcode-链表中间节点

876. 链表的中间结点 题目 给你单链表的头结点 head &#xff0c;请你找出并返回链表的中间结点。 如果有两个中间结点&#xff0c;则返回第二个中间结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[3,4,5] 解释&#xff1a;链表只有一个中间…