C/C++之自定义类型(结构体,位段,联合体,枚举)详解

个人主页:点我进入主页

专栏分类:C语言初阶      C语言程序设计————KTV       C语言小游戏     C语言进阶

C语言刷题

欢迎大家点赞,评论,收藏。

一起努力,一起奔赴大厂。

目录

个人主页:点我进入主页

 

1.前言

2.结构体

2.1结构体声明

2.2结构体初始化

2.3结构体的自引用

2,4结构体的内存对齐

 3.位段

3.1什么是位段

3.2位段的内存分配

3.3位段的跨平台性

4.枚举 

4.1枚举声明

4.2枚举的优点

4.3枚举的使用

5.联合体

5,1联合体的声明

5.2联合体的大小

5.3联合体的使用


 

1.前言

        随着我们深入学习C语言,我们发现单纯的int,char,double,float类型已经不能满足我们的需要了,那C语言是否还有其他的类型呢,事实上还有一类那就是结构体,结构体是我们自己创造的一种类型,它可以包含C语言的所有类型,结构体是什么呢?结构体如何创建?结构体如何初始化?等问题我会给大家详细解析

2.结构体

2.1结构体声明

        对于结构体如何声明,例如我们想创建一个关于学生的信息,包括名字和学号我们可以如下操作:

struct student{int num;cahr name[50];
};

2.2结构体初始化

        对于结构体的初始化我们可以看如下代码:

#include <stdio.h>
struct student {int num;char name[50];
};
int main()
{struct student s[3] = { {1,"zhansan"},{2,"lisi"} };int i;for (i = 0; i < 2; i++){printf("%d %s\n", s[i].num, s[i].name);}return 0;
}

        对于结构体的访问我们需要用到“.”或者"->"进行访问“.”就是让面的操作对于“->”就是传址也就是指针我们可以进行如下操作,代码如下:

#include <stdio.h>
struct student {int num;char name[50];
};
int main()
{struct student s[3] = { {1,"zhansan"},{2,"lisi"} },*p=s;int i;for (i = 0; i < 2; i++){printf("%d %s\n", p->num ,p->name );p++;}return 0;
}

2.3结构体的自引用

        对于结构体,还有一种操作就是结构体的自引用,我们还可以理解为结构体嵌套结构体具体的代码如下:

struct student {int num;char name[50];
};
struct Std {struct student std[3];int gard;
};

        对于striuct Std类型的变量初始化和struct student类型的相似只是多次操作即可例如s.std[0].num=1;

2,4结构体的内存对齐

        结构体中有一个很有意思的现象,代码如下:

#include <stdio.h>
struct student1 {char ch1;char ch2;int i;
};
struct student2 {char ch1;int i;char ch2;
};
int main()
{printf("%d\n", sizeof(struct student1));printf("%d\n", sizeof(struct student2));
}

代码输出的结果为

f62c784685694e7c95111a7c38acef0a.png

        问什么会这样呢?我们一般的理解是char占用1个字节,int占4个字节,共占6个字节,这就和结构体的内存对齐有关了 ,首先得掌握结构体的对齐规则:

1. 第一个成员在与结构体变量偏移量为0的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。VS中默认的值为8
3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整
体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
为什么存在内存对齐?

我们可以理解为第一个占0位置,对齐数就是编译器的默认值和成员大小的较小值,偏移量的初始位置为对齐数的倍数,最后所占的字节为最大成员的倍数。 

例如我们第一个结构体进行画图讲解:

 ce1799fbd4da4589b25022f8d8580b5f.png

         ch1占0的位置,ch2的对齐数是1占1的位置,num的对齐数是4占4的位置,共占8个8是4的倍数故占8个字节。

对于对齐数的默认值我们可以用#pragma pack()进行修改,例如#pragma pack(8);

大部分的参考资料都是如是说的:

1. 平台原因(移植原因):
不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特
定类型的数据,否则抛出硬件异常。
2. 性能原因:
数据结构(尤其是栈)应该尽可能地在自然边界上对齐。
原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访
问。

总体来说:

结构体的内存对齐是拿空间来换取时间的做法。
那在设计结构体的时候,我们既要满足对齐,又要节省空间,如何做到:
让占用空间小的成员尽量集中在一起。

 3.位段

3.1什么是位段

        位段和结构体类似,它的成员是int,unsigned int ,signed int,它的形式是类型 +变量名+: 字节数,它的详细代码可以理解为:

struct num {int a : 2;int b : 3;int i : 30;
};

3.2位段的内存分配

1. 位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型
2. 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。
3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。

 例如如下代码的内存分配:

#include <stdio.h>
struct S
{
char a:3;
char b:4;
char c:5;
char d:4;
};
int main()
{struct S s = { 0 };s.a = 10;s.b = 12;s.c = 3;s.d = 4;return 0;
}

我们可以进行画图理解:

        由于位段的不确定性所以我我们在一个字节中不知道是占高位还是低位,我们正常思维是占低位,在占低位时可以理解为

0f0d17f8581c4e8a85d6bf95ce61d081.png

        这样第一个字节为01100010为62,第二个字节为00000011为03,第三个字节为00000100为04,真实的储存是不是我们理解的呢?我们进入调试看一看内存

571504a1a14f4bc383e6a33a4b49827d.png

        于是这样就形成了位段,对于位段占几个字节我们可以利用sizeof()进行操作得到它占用几个字节 。

3.3位段的跨平台性

1. int 位段被当成有符号数还是无符号数是不确定的。
2. 位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机
器会出问题。
3. 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
4. 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是
舍弃剩余的位还是利用,这是不确定的

位段在信息传输时有很重要i的作用,在这里不做讲解。

4.枚举 

4.1枚举声明

enum s {blue,red,back
};

        枚举和#define一样在上面的代码中blue相当于#define blue 0,red相当于 #define red 1,back相当于#define back 2。难道只能从0开始吗?显然是不可能的,我们应该如何修改?如下:

enum s {blue=3,red=2,back=10
};

4.2枚举的优点

我们可以使用 #define 定义常量,为什么非要使用枚举?
枚举的优点:
1. 增加代码的可读性和可维护性
2. 和#define定义的标识符比较枚举有类型检查,更加严谨。
3. 防止了命名污染(封装)
4. 便于调试
5. 使用方便,一次可以定义多个常量

4.3枚举的使用

枚举的使用主要就是switch case语句中例如

 

enum s {blue,red,back
};
int main()
{int a = 1;switch (a){case blue:; break;case red:; break;case back:; break;}return 0;
}

5.联合体

5,1联合体的声明

联合体声明如下:

union Un1
{char c[5];int i;
};

5.2联合体的大小

联合的大小至少是最大成员的大小。
当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。

联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)。

对于联合体的成员共同占用一个空间,我们可以做一个测试,代码如下:

#include <stdio.h>
union Un1
{char c[5];int i;
};int main()
{union Un1 u1;printf("%p\n", &u1.c);printf("%p\n", &u1.i);printf("%p\n", &u1);
}

我们运行结果如下:

cb3aa2523a2c448a981860bdaf716658.png

因此我们可以得到联合体存储的方式

6a359a82e91c4669a91410d2317d0e9b.png

 对于如何计算联合体的大小,我们可以看一下代码:

#include <stdio.h>
union Un1
{char c[5];int i;
};
union Un2
{short c[7];int i;
};
int main()
{printf("%d\n", sizeof(union Un1));printf("%d\n", sizeof(union Un2));
}

对于Un1我们可以画成a726c0b001d242fd9f0614e7d9ae6a79.png

        对于c占5个字节,i占4个字节,但是c是char类型是1个字节,成员最大的为4,由于需要占最大成员的倍数 故占8个字节。Un2也是同样的操作,short占2个字节,共14个字节,int占4个字节,共占用16个字节。

5.3联合体的使用

        我们知道联合体是一种节省空间存储方式,我们可以把它用在多个不共同使用的多i个结构体创建上大致可以理解为

struct num{

        union u1{

               结构体1;

               结构体2;

                ......

        };

};

今天的内容就结束了,欢迎大家来三连。 

 

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

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

相关文章

React笔记:useState

1 介绍 useState 是 React 中一个非常重要的钩子&#xff08;Hook&#xff09;&#xff0c;允许在函数组件中添加状态。 2 基本用法 useState 是一个函数&#xff0c;它接收一个参数&#xff08;初始状态值&#xff09;并返回一个数组。 返回的这个数组包含两个元素&#xf…

JAXB 使用记录 bean转xml xml转bean 数组 继承

JAXB 使用记录 部分内容引自 https://blog.csdn.net/gengzhy/article/details/127564536 基础介绍 JAXBContext类&#xff1a;是应用的入口&#xff0c;用于管理XML/Java绑定信息 Marshaller接口&#xff1a;将Java对象序列化为XML数据 Unmarshaller接口&#xff1a;将XML数…

滚珠螺母在工业机器人中的应用优势

工业机器人是广泛用于工业领域的多关节机械手或多自由度的机器装置&#xff0c;具有一定的自动性&#xff0c;可依靠自身的动力能源和控制能力实现各种工业加工制造功能。滚珠螺母作为工业机器人中的重要传动配件&#xff0c;在工业机器人的应用中有哪些优势呢&#xff1f; 1、…

STM32 CubeMX PWM三种模式(HAL库)

STM32 CubeMX PWM两种模式&#xff08;HAL库&#xff09; STM32 CubeMX STM32 CubeMX PWM两种模式&#xff08;HAL库&#xff09;一、互补对称输出STM32 CubeMX设置代码部分 二、带死区互补模式STM32 CubeMX设置代码 三、普通模式STM32 CubeMX设置代码部分 总结 一、互补对称输…

API接口安全运营研究

根据当前API技术发展的趋势&#xff0c;从实际应用中发生的安全事件出发&#xff0c;分析并讨论相关API安全运营问题。从风险角度阐述了API接口安全存在的问题&#xff0c;探讨了API检测技术在安全运营中起到的作用&#xff0c;同时针对API安全运营实践&#xff0c;提出了几个方…

[ICCV-23] DeformToon3D: Deformable Neural Radiance Fields for 3D Toonification

pdf | code 将3D人脸风格化问题拆分为几何风格化与纹理风格化。提出StyleField&#xff0c;学习以风格/ID为控制信号的几何形变残差&#xff0c;实现几何风格化。通过对超分网络引入AdaIN&#xff0c;实现纹理风格化。由于没有修改3D GAN空间&#xff0c;因此可以便捷实现Edit…

代码随想录算法训练营第23期day17| 110.平衡二叉树、257. 二叉树的所有路径、404.左叶子之和

目录 一、&#xff08;leetcode 110&#xff09;平衡二叉树 二、&#xff08;leetcode 257&#xff09;二叉树的所有路径 三、&#xff08;leetcode 404&#xff09;左叶子之和 一、&#xff08;leetcode 110&#xff09;平衡二叉树 力扣题目链接 状态&#xff1a;已AC 求深…

如何在 Spring Boot 中使用 WebSocket

在Spring Boot中使用WebSocket构建实时应用 WebSocket是一种用于实现双向通信的网络协议&#xff0c;它非常适合构建实时应用程序&#xff0c;如在线聊天、实时通知和多人协作工具。Spring Boot提供了对WebSocket的支持&#xff0c;使得在应用程序中集成WebSocket变得非常容易…

QTableWidget 表格部件

QTableWidget是QT中的表格组件类。一般用来展示多行多列的数据&#xff0c;是QT中使用较多的控件之一。1、QTableWidgetItem对象 QTableWidget中的每一个单元格都是一个QTableWidgetItem对象&#xff0c;因此先介绍下QTableWidgetItem的常用方法。 1.1、设置文本内容 void QT…

可拓展的低代码全栈框架

尽管现在越来越多的人开始对低代码开发感兴趣&#xff0c;但已有低代码方案的局限性仍然让大家有所保留。其中最常见的担忧莫过于低代码缺乏灵活性以及容易被厂商锁定。 显然这样的担忧是合理的&#xff0c;因为大家都不希望在实现特定功能的时候才发现低代码平台无法支持&…

ref与DOM-findDomNode-unmountComponentAtNode知识点及应用例子

​​​​​​http​​​http://t.csdnimg.cn/og3BI 知识点讲解↑ 需求: (下载/导出 用post请求时:) 实例: react部分代码 1、点击下载按钮&#xff0c;需要传给后端数据&#xff0c;到数据扁平&#xff0c;不是那么复杂&#xff0c;只需url地址即可完成下载&#xff0c;后端…

神经网络(MLP多层感知器)

分类 神经网络可以分为多种不同的类型&#xff0c;下面列举一些常见的神经网络类型&#xff1a; 前馈神经网络&#xff08;Feedforward Neural Network&#xff09;&#xff1a;前馈神经网络是最基本的神经网络类型&#xff0c;也是深度学习中最常见的神经网络类型。它由若干个…

SpringBoot 如何使用 Sleuth 进行分布式跟踪

使用Spring Boot Sleuth进行分布式跟踪 在现代分布式应用程序中&#xff0c;跟踪请求和了解应用程序的性能是至关重要的。Spring Boot Sleuth是一个分布式跟踪解决方案&#xff0c;它可以帮助您在分布式系统中跟踪请求并分析性能问题。本文将介绍如何在Spring Boot应用程序中使…

java模拟GPT流式问答

流式请求gpt并且流式推送相关前端页面 1&#xff09;java流式获取gpt答案 1、读取文件流的方式 使用post请求数据&#xff0c;由于gpt是eventsource的方式返回数据&#xff0c;所以格式是data&#xff1a;&#xff0c;需要手动替换一下值 /** org.apache.http.client.metho…

数据库系统工程师------流水线

流水线 流水线周期&#xff1a;工序中最长的那段执行时间。 流水线计算公式&#xff1a;第一条指令计算时间 &#xff08;指令条数 - 1&#xff09;*流水线周期。 流水线吞吐率&#xff1a;指单位时间内流水线完成的任务数量或输出的结果数量。 流水线的加速比&#xff1a;完…

机器学习与模式识别作业----决策树属性划分计算

文章目录 1.决策树划分原理1.1.特征选择1--信息增益1.2.特征选择2--信息增益比1.3.特征选择3--基尼系数 2.决策树属性划分计算题2.1.信息增益计算2.2.1.属性1的信息增益计算2.2.2.属性2的信息增益计算2.2.3.属性信息增益比较 2.2.信息增益比计算2.3.基尼系数计算 1.决策树划分原…

VMware Workstation Player 17 下载安装教程

虚拟机系列文章 VMware Workstation Player 17 免费下载安装教程 VMware Workstation 17 Pro 免费下载安装教程 windows server 2012安装教程 Ubuntu22.04.3安装教程 FTP服务器搭建 VMware Workstation Player 17 下载安装教程 虚拟机系列文章前言一、 VMware Workstation Pla…

手机APP也可以学习Sui啦,通过EasyA开启你的学习之旅

Sui基金会与EasyA合作&#xff0c;开发了一门面向初学者的Sui课程。这一适用于Android和iOS移动端的学习体验&#xff0c;是进入更广泛的Sui社区和生态系统的入口。在这门课程中&#xff0c;学习者将以有趣和互动的方式获得对Sui的基本了解&#xff0c;最终能够在测试网络上部署…

Wifi列表扫描和Wifi链接

上面的截图&#xff0c;就是本文要介绍的主要功能。 1.准备工作&#xff0c;声明权限&#xff1a; <uses-permission android:name"android.permission.CHANGE_WIFI_STATE" /><uses-permission android:name"android.permission.ACCESS_WIFI_STATE&quo…

10.selenium进阶

文章目录 1、嵌套网页1、1 什么是嵌套页面1、2 selenium获取嵌套页面的数据 2、执行JavaScript代码3、鼠标动作链4、selenium键盘事件5、其他方法5、1 选择下拉框5、2 弹窗的处理 6、selenium设置无头模式7、selenium应对检测小结 1、嵌套网页 ​ 在前端开发中如果有这么一个需…