结构体||联合体

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.rhkb.cn/news/208267.html

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

相关文章

基于SSM的网上书城

简介 本系统主要分为前台和后台,前台网页主要是面向用户的,用户注册登录后网上书城可以进行下单购买图书,主要功能有图书基本信息的查询、用户登录和注册、图书搜索、添加购物车、购买、订单查询等功能,后台是管理员进入的&#x…

Python基础学习快速入门

文章目录 Number变量String字符串Def函数Class类List列表Tuple元组Dictionary字典Set集合值与引用类型if条件控制Loop循环 Number变量 python直接赋值,不需要定义变量类型。不需要**,逗号结尾符 使用print**直接进行输出 #赋值 a 1.0 print(a)a 7 print(a)p…

Selenium 学习(0.17)——软件测试之测试用例设计方法——白盒测试——逻辑覆盖法(条件覆盖和条件判定覆盖)

条件覆盖 设计测试用例,使每个判断中每个条件的可能取值至少满足一次。 条件判定覆盖 通过设计足够的测试用例,满足如下条件: 所有条件的可能至少执行一次的取值 所有判断的可能结果至少执行一次 条件判定覆盖同时满足判定覆…

12.1平衡树(splay),旋转操作及代码

平衡树 变量定义 tot表示结点数量,rt表示根的编号 v[i]表示结点i的权值 fa[i]表示结点i的父亲节点 chi[i][2]表示结点i的左右孩子 cnt[i]表示结点i的权值存在数量,如1123,v[3]1,则cnt[3]2;就是说i3的三号结点的权值为1&…

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

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

hls实现播放m3u8视频将视频流进行切片 HLS.js简介

github官网GitHub - video-dev/hls.js: HLS.js is a JavaScript library that plays HLS in browsers with support for MSE.HLS.js is a JavaScript library that plays HLS in browsers with support for MSE. - GitHub - video-dev/hls.js: HLS.js is a JavaScript library …

无桌面版docker在Ubuntu系统上安装

目录 注意 系统要求 卸载旧版本 安装 使用apt存储库安装 1. 设置 Docker 的apt存储库。 2. 安装Docker软件包 3. 通过运行镜像来验证Docker Engine安装是否成功 hello-world。 从包中安装 1. 进入 https://download.docker.com/linux/ubuntu/dists/。 2. 在列表中选择…

ubuntu22.04新机使用(换源,下载软件,安装显卡驱动,锁屏长亮)

换源 国内有很多Ubuntu的镜像源,包括阿里的、网易的,还有很多教育网的源,比如:清华源、中科大源。推荐使用中科大源,快得很。 /etc/apt/sources.list编辑/etc/apt/sources.list文件, 在文件最前面添加以下条目(操作前…

KEPserver和S7-200SMART PLC通信配置

KEPserver和S7-1200PLC通信配置,请查看下面文章链接: https://rxxw-control.blog.csdn.net/article/details/134683670https://rxxw-control.blog.csdn.net/article/details/134683670 1、OPC通信应用 2、选择Siemens驱动 3、添加S7-200设备

k8s部署jenkins

1.先决条件 1.因为国内的容器镜像加速器无法实时更新docker hub上的镜像资源.所以可以自己进行jenkins的容器镜像创建,. 2.这里用到了storageClass k8s的动态制备.详情参考: k8s-StoargClass的使用-基于nfs-CSDN博客 3.安装docker服务.(用于构建docker image) 2.构建jenki…

C++学习之路(十六)C++ 用Qt5实现一个工具箱(为屏幕颜色提取功能增加一个点击复制的功能)- 示例代码拆分讲解

上篇文章,我们用 Qt5 实现了在小工具箱中添加了《颜色代码转换和屏幕颜色提取功能》功能。今天我们把屏幕颜色提取的功能再扩展一下,让它可以点击复制吧。下面我们就来看看如何来规划开发这样的小功能并且添加到我们的工具箱中吧。 老规矩,先…

AntDB数据库:从海量数据处理,到5G计费商用核心

AntDB数据库自2008年研发面世以来,首先被应用于运营商的核心系统,满足运营商海量数据处理的需求。随着数字科技的不断发展,AntDB也在不断地更新迭代,逐渐地为更多行业与客户提供更全面的服务。5G时代来临,AntDB抓住发展…

Linux 磁盘分区处理

最近实施过程中遇到客户提供给我们的服务器操作系统和Docke容器环境都已经安装完成,但磁盘的分区没有进行整理好。磁盘总共270G,系统安装分配了60G,剩余未创建分配需要处理。由于分区情况每家不一样,但大致流程都是相同的&#xf…

uniapp地图基本使用及解决添加markers不生效问题?

uniapp地图使用 App端 通过 nvue 页面实现地图 文章目录 uniapp地图使用效果图templatejs添加 marker使用地图查看位置移到到当前位置 效果图 template <template><view class"mapWrap"><!-- #ifdef APP-NVUE --><map class"map-containe…

一篇带你串通数据结构

文章目录 导论数据结构的定义数据结构在计算机科学中的重要性为什么学习数据结构很重要 1、基本概念1.1、数据、数据元素和数据项的概念1.2、数据对象与数据结构的关系1.3、逻辑结构与物理结构 2、线性结构2.1、数组2.2、链表2.3、栈2.4、队列 3、非线性结构3.1、树3.2、图 4、…

P1 什么是链表 C语言简单易懂

目录 前言 01 什么是链表 02 数组的特点 03 数组的缺点 3.1 删除数组其中一个元素 3.2 数组增加某个节点 04 链表 前言 &#x1f3ac; 个人主页&#xff1a;ChenPi &#x1f43b;推荐专栏1: 《 C 》✨✨✨ &#x1f525; 推荐专栏2: 《 Linux C应用编程&#xff08;概念…

【1】基于多设计模式下的同步异步日志系统

1. 项目介绍 本项⽬主要实现⼀个⽇志系统&#xff0c; 其主要⽀持以下功能: • ⽀持多级别⽇志消息 • ⽀持同步⽇志和异步⽇志 • ⽀持可靠写⼊⽇志到控制台、⽂件以及滚动⽂件中 • ⽀持多线程程序并发写⽇志 • ⽀持扩展不同的⽇志落地⽬标地 2. 开发环境 • CentOS 7 • vs…

存储虚拟化的写入过程

存储虚拟化的场景下&#xff0c;整个写入的过程。 在虚拟机里面&#xff0c;应用层调用 write 系统调用写入文件。write 系统调用进入虚拟机里面的内核&#xff0c;经过 VFS&#xff0c;通用块设备层&#xff0c;I/O 调度层&#xff0c;到达块设备驱动。虚拟机里面的块设备驱动…

K7系列FPGA多重启动(Multiboot)

Xilinx 家的 FPGA 支持多重启动功能&#xff08;Multiboot&#xff09;&#xff0c;即可以从多个 bin 文件中进行选择性加载&#xff0c;从而实现对系统的动态更新&#xff0c;或系统功能的动态调整。 这一过程可以通过嵌入在 bit 文件里的 IPROG 命令实现上电后的自动加载。而…

自定义类型-结构体,联合体和枚举-C语言

引言 能看到结构体&#xff0c;说明C语言想必学习的时间也不少了&#xff0c;在之前肯定也学习过基本数据类型&#xff0c;包括整型int&#xff0c;浮点型float等等。可是在日常生活中&#xff0c;想要描述一个事物并没有那么简单。比如&#xff0c;你要描述一本书&#xff0c…