结构体||联合体

1.结构体

1.1实际生活中一些东西往往有多个元素组成。如一名学生有身高、体重、名字、学号等。这时候就需要用到结构体。

结构体是一些值的结合,这些值被称为成员变量。结构体的每个成员可以是不同类型的变量,如:标量、数组、指针、甚至是其他结构体。

1.2结构的声明(struct是结构体关键字)

struct tag//结构体类型

{

        member-list//结构体成员

} variable-list//变量

如描述一个学生时

1.先定义结构体类型,在定义结构体变量

struct student

{

        char name[20];

        double height;

        int age;

} ;

struct student stu1,stu2;

2.定义结构体和变量 

struct student

{

        char name[20];

        double height;

        int age;

}stu1,stu2 ;

3.直接定义变量(匿名结构体)

struct

{

        char name[20];

        double height;

        int age;

}stu1;

·匿名结构体如果没有对结构体进行重命名的话,基本上只能使用一次。 

·结构体定义不分配地址,结构体变量会分配地址。

·结构体变量的声明必须在主函数上或者主函数中

1.3结构体的初始化(基于上述描述学生代码)

int main()

{

        struct stu s1={"zhangsan",1.85,18};

        struct stu s2={"lisi",1.78,16};

        ……;

}

1.4结构体的访问

1.结构体成员的直接访问:成员访问操作符(.)

 s1.name

 s1.age

2. 结构体成员间接访问:

stuct student*p=&s1;

p->age=18;

p->name="zhangsan"

1.5typedef关键字与结构体

typedef struct student

{

        char name[20];

        int age;

} stu;//相当于struct student;

stu s1={"zhangsan",18};

stu*p=&s1;

typedef主要目的是使结构体表达更加简洁,可以理解为给结构体重命名。

 1.6结构体的自引用

struct student

{

        int age;

        struct student;

}; 

上述写法正确吗?我们从sizeof(student)角度来分析,一个结构体包含自己显然它的大小就是无穷大,这是不合理的。所以想要一个结构体进行自引用,应该让结构体包含自己的指针

struct student

{

        int age;

        struct student*NEXT;

} ;

2.1结构体内存对齐

结构体的创建与初始化我们已经掌握了,接下来我们来探讨一个问题:计算结构体的大小,这就联系到结构体内存对齐

1.对齐规则

1.1结构体的第一个成员对齐到和结构体变量起始位置偏移量为0的地址出
1.2其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处

          对齐数=编译器默认对齐数和该成员变量大小的较小值

          -VS中默认对齐数是8

          -Linux和gcc中没有默认对齐数,对齐数就是成员自身的大小

1.3结构体的总大小为最大对齐数的整数倍
1.4如果一个结构体中嵌套了别的结构体,嵌套结构体对齐到自己成员中最大对齐数的整数倍

 

由上面两张图可以发现结构体成员定义先后顺序不同,结构体的大小也不一样。这是为什么呢?接下来就用结构体内存对齐来讲解下。(VS环境)

 

第一幅图a填在偏移量为0的地方,i为int类型对齐数为4所以必须填在4的整数倍的位置,所以i填在4处,b为char类型对齐数为1所以只要填在1的整数倍的位置 所以接在i下面填在8出但是0~8的大小为9,该结构体中最大对齐数是i的对齐数4,9不是4的倍数所以结构体最后大小是12。

图二同理,可以自己去验证下。

2.为什么会存在内存对齐

1.平台原因(移植原因):

不是所有的硬件平台都能访问任意地址上的任意数据的,某些平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

2.性能原因

数据结构(尤其是栈)应该是尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内容,处理器需要作两次内存访问;而对齐的内容访问仅需要访问一次。假设处理器总是从内存中去8个字节,则地址必须是8的倍数,如果我们能保证将所有的double类型的数据都对齐成8的倍数,那么就可以用一个内存操作来读或者写值了。否则,我们可能需要执行两次访问,因为对象可能被分在两个8字节内存块中。

总的来说:结构体内存对齐就是那空间来换时间的做法。

所以如果我们在设计结构体的时候既要满足对齐又要节省空间,就要对定义成员的顺序进行一定的规划。如上面两张图的差别。

3.修改默认对齐值(利用#pragma)

#pragma pack(4)//修改默认对齐数为4

struct  s

{

        ……

};

#pragma pack()//取消设置的对齐数,还原为默认

int main()

{

}

3.1结构体实现位段

1.什么是位段
1.1位段的成员必须是Int、unsigned Int、signed int 、char。在c99中位段成员的类型也可以选择其他类型 。
1.2位段的成员后边有一个冒号和一个数字。

位段的目的:节省空间

struct A

{

        int _a:2;

        int _b:5;这里的数字是指比特位(bit)

        int _c:10;

        int _d:30;

};

A就是位段的类型。位段A所占大小为8字节(原理:2+5+10+30=47bit ,一个int(整型)四个字节,32个比特位,显然一个整型不足以存放位段A,所以需要两个整型,也就是8个字节)

 1.4位段的空间上是按照需要以4个字节(int)或者1个字节(char)的方式来开辟。
1.5位段涉及很多不确定的因素,位段是不跨平台的,注重可移植的程序应该避免使用位段
1.6开辟位段空间

        VS环境下的位段开辟:1.从右向左使用。

                                              2.如果剩余的空间不够下一个成员使用就浪费。

struct S

{

        char a:3;

        char b:3;

        char c:4;

        char d:5;

};

struct S s={0};

s.a=10;

s.b=12;

s.c=6;

s.d=8;

 

可以看到内存中确实是我们所推理的那样,存放22 06 08 

2联合体

2.1联合体的声明

联合体也和结构体一样由一个或者多个元素组成,联合体的特点是所有成员共用一块内存空间。所以联合体也叫共用体 

 union Un

{

        char a;

        int i;

};

int main()

{

        union Un un={0};//联合变量定义

        printf(“%d”,sizeof(un));//4   

}

2.2联合体的特点

为什么上述声明的联合体大小是4个字节,上面讲到联合体成员是共用一块内存空间的,这样就使联合体的大小,至少是最大成员的大小。

在描述不同的商品比如:图书,杯子,衬衫时。每一种商品都有价格、库存量等但是他们又都有单独特有的属性页数、设计、尺寸。这个时候如果用结构体来描述就会十分复杂,而用联合体就可以节省空间。

最后来利用联合体特有的特性来实现上一章的大小端判断

int judge()

{

        union  un

        {

                int i;

                char a;//a占一个字节在联合体中与i的第一个字节共用一块内存空间

        }

        un.i=1;

        return un.a;

}

int main()

{

        if(judge())

                printf("小端”);

        else

                printf("大端");

}

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

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

相关文章

基于模型生成代码(MBD)

基于模型生成代码(MBD) 1、MBD的基本概念 图形化模型:MBD主要使用图形化的方式来表示系统。这些模型可以是控制流程图、状态机、或者其他形式的图形表示,能够清晰地展示系统的行为和逻辑。从概念到实现:在MBD中,整个开发流程从概念设计开始,直至实现和测试,都围绕模型…

基于2D激光雷达匹配的充电桩位姿检测

原理 1. 激光雷达滤波,滤除太远的雷达数据,并降采样 2. 对雷达数据进行分割聚类出candidates 3. 通过策略,过滤掉大部分不符合的candidates 4. 对candidates与充电桩模板数据进行PCA、ICP匹配 5. 选择距离最小或者得分最高的一帧作为输出…

传纸条(算法题)

题目来源 传纸条 题目描述: 小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题。一次素质拓展活动中,班上同学安排做成一个m行n列的矩阵,而小渊和小轩被安排在矩阵对角线的两端,因此,他们就无法…

提高wordpress网站收录速度,设置wp后台的“更新服务”功能

搜索引擎会按照某个规律定期的来抓取网站的内容,其抓取你网站的频率一般和网站的更新速度有关,如果网站内容更新频繁,那么网络蜘蛛也会频繁的访问网站。每天坚持更新文章显然这对一般个人博主来说有难度,另一个方法就是每当我们发…

redis——布隆过滤器

一:布隆过滤器是什么? 由一个初值都为零的bit数组和多个哈希函数构成,用来快速判断集合中是否存在某个元素,不保存数据信息,只是在内存中做一个是否存在的标记 二:布隆过滤器能干什么? 高效…

HTB_Archetype攻击全流程

Archetype (SMB、SQL Server xp_cmdshell、反弹shell、winPEASx64、psexec远程连接) TASK 1 问题: 哪个TCP端口托管着数据库服务器?目的: 识别运行数据库服务的端口,通常通过端口扫描(如使用nmap)来完成。 TASK 2 问题: 通过S…

滑动平均+TTA

给定一堆二维图像,要拼成三维,然后要在x,y,z上分别预测,预测要预测一个二维patch,还要tta,最后平均结果 import torchM, N, R 40, 40, 4 CUT_SIZE 10 OFFSET 5def get_data():# (M, N) * Rt…

中国湖泊面积-水位长时序数据产品(2000-2020)

今天我们分享中国湖泊面积-水位长时序数据产品(2000-2020) 该数据集包含中国典型湖泊2000-2020年最大水体面积、多年平均面积、水位变化速率及空间分布矢量。 数据溯源信息 「数据来源描述」Landsat、HJ、ZY、Jason、ENVISAT、Cryosat、ICESat和HY 「数…

力扣 572. 另一棵树的子树

目录 1.解题思路2.代码实现 1.解题思路 首先先要有一个判断根据两个根节点判断两个树是否相等的接口,然后再利用递归,在需要被比较的树里进行前序遍历来得出是否有子树. 2.代码实现 bool issame(struct TreeNode* root, struct TreeNode* subRoot) {if…

dockerfile文件:copy和add 异同

相同点: 复制文件或目录: 无论是 COPY 还是 ADD 都可以将文件或目录从构建上下文复制到容器中。支持源路径和目标路径: 两者都需要指定源路径和目标路径,用于指定要复制的文件或目录在主机上的位置以及在容器中的目标路径。 不同…

Boost:多进程间同步文件锁

Linux(编程):多进程同步-文件锁_linux 进程锁-CSDN博客 介绍了Linux的文件锁,Boost对文件锁也进行了封装 1.创建文件锁 #include <boost/interprocess/sync/file_lock.hpp> boost::interprocess::file_lock flock("my_file"); 注:文件必须存在,且运行当前…

责任等同于背锅?

本文首发于个人网站「BY林子」&#xff0c;转载请参考版权声明。 01 两个真实的故事 故事一 X公司IT质量管理部门在做质量的规范化管理&#xff0c;定义实践标准规范、模板、指南等&#xff0c;以指导各个团队因为实践不一致带来的问题&#xff0c;帮助各个团队更规范地开发和…

Nginx实现(负载均衡)

在 Nginx 中搭建负载均衡&#xff08;Load Balancing&#xff09;可以将来自客户端的请求分发到多个后端服务器上&#xff0c;从而提高应用程序的可用性、性能和扩展性。Nginx 通过反向代理和负载均衡模块实现这一功能。以下是一个基本的负载均衡配置示例&#xff1a; 安装和配…

【UBUNTU】随手记

目录 1. 更新软件到最新版本1.1 CMAKE [U20]1.2 GIT1.3 WIRESHARK1.4 LLVM 2. 设置代理2.1 APT2.2 GIT2.3 WGET2.4 PIP 1. 更新软件到最新版本 1.1 CMAKE [U20] 参考&#xff1a;https://apt.kitware.com/ # 1. 更新基础库 sudo apt-get update# 2. 安装可能需要的工具 sudo…

RocketMQ事务消息源码解析

RocketMQ提供了事务消息的功能&#xff0c;采用2PC(两阶段协议)补偿机制&#xff08;事务回查&#xff09;的分布式事务功能&#xff0c;通过这种方式能达到分布式事务的最终一致。 一. 概述 半事务消息&#xff1a;指的是发送至broker但是还没被commit的消息&#xff0c;在半…

<软考>软件设计师-1计算机组成与结构(总结)

(一)计算机系统基础知识 1 计算机硬件组成 计算机的基本硬件系统由运算器、控制器、存储器、输入设备 和 输出设备 5大部件组成。 1 运算器、控制器等部件被集成在一起统称为中央处理单元(CPU) 。CPU是硬件系统的核心&#xff0c;用于数据的加工处理&#xff0c;能完成各种算…

2023.11.27【读书笔记】|医疗科技创新流程(前言)

目录 注重价值关键要素如何解决价值问题&#xff1f;注重三个关键点价值探索价值预测价值定位 中国视角背景挑战战术 洞察过程发现需求发现需求筛选 发明概念产生概念选择 发挥战略发展商业计划 注重价值 在美国&#xff0c;医疗费用的增长率已经多年超过GDP增长率&#xff1b…

Redis--11--Redis事务的理解

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 Redis事务事务回滚机制Redis 事务是不支持回滚的&#xff0c;不像 MySQL 的事务一样&#xff0c;要么都执行要么都不执行&#xff1b; Redis的事务原理 Redis事务 …

第九节HarmonyOS 常用基础组件1-Text

一、组件介绍 组件&#xff08;Component&#xff09;是界面搭建与显示的最小单位&#xff0c;HarmonyOS ArkUI声名式为开发者提供了丰富多样的UI组件&#xff0c;我们可以使用这些组件轻松的编写出更加丰富、漂亮的界面。 组件根据功能可以分为以下五大类&#xff1a;基础组件…

微服务实战系列之MemCache

前言 书接前文&#xff0c;马不停蹄&#xff0c;博主继续书写Cache的传奇和精彩。 Redis主要用于数据的分布式缓存&#xff0c;通过设置缓存集群&#xff0c;实现数据的快速响应&#xff0c;同时也解决了缓存一致性的困扰。 EhCache主要用于数据的本地缓存&#xff0c;因无法保…