当前位置: 首页 > news >正文

一次通关结构体、位断、联合体和枚举这四大痛点

导读:

一到七是结构体的内容,其中重中之重是第七点,结构体大小的计算

第八点是对位断的讲解

第九点是联合体,讲解了两个联合体的应用

第十点是枚举,但不是很重点

一.什么是结构体

1.结构体:其实就是自定义数据类型,结构是值的集合,这些值可以是不同类型的变量

(变量:标量,指针,数组,甚至调用其他结构体)

二.结构体语法格式

2.1先声明类型再定义变量

记得声明在int主函数之前

2.2声明的同时定义

2.3匿名结构体

匿名结构体类型,只能使用一次,后期不能使用这个类型来创建变量,因为没有名字
struct
{
……
}x,y,z
struct
{
……
}x,y,z

2.4结构体的自引用

(数据结构里链表的节点)

struct jiedian struct

{ {

int date; int date;//数据域

struct jiedian next; struct jiedian* next //指针域

}; };

左边不可以的呀,因为左边如果成立,那么struct jiedian占多少字节,有无限个节点,无限大?显然不可能,而且他还包含了一个date,成员加起来比自己都大

改进:右边一半存数据,一半存指针

(如果重命名【详见第六点】为jiedain,不可以把右边的struct jiedain*next,写成jiedain*next,这里面是先定义然后才重命名的,而不是直接把结果拿来使用)

三.结构体的访问

3.1普通结构体的访问

在键盘上找到.这个操作符

想给结构体里的变量赋值,只需在变量名之后点.一下就可以大胆赋值了

他的初始化与数组类似,一般是按成分顺序,如图

不按照顺序初始化需要结构成员访问操作符.(点)

大概为结构体变量.结构体成员名
如果是.cpp后缀的文件就没办法打乱顺序初始化,.c后缀的才行

2.5变量可以随意设置在这些位置

3.2结构体指针访问

使用->这个操作符

如图,这样可以开始对s1变量大胆赋值了

四.结构体里嵌套结构体

类比数组,二维数组是一个特殊的一维数组,只不过他的元素从单个属性变成单个数组

对应的,结构体里面可以有一个结构体来充当元素

所以,你掌握了结构体嵌套结构体,演示如下

五.结构体数组

5.1结构数组定义

相同的元素可以用数组装起来

相同的结构体元素同样可以用结构体装起来,演示如下

5.2结构体传参

如图,可以把结构体当做参数传递到函数里面

但是更推荐传址调用,传值调用理论上还要再创建一块空间来存贮这个结构体里的变量,对时间和空间都有开销

六.结构体重命名

结构体每次定义变量都要像例如 struct Stu s1这样命名

但如图重命名之后,struct Stu==N,省去大量代码

七.结构体内存对齐(计算大小)

7.1引入

1.

如图,只不过是把char 和int 调换了顺序,内容保持不变,但用sizeof算出来的大小是不一样的

这就涉及到大小的计算,实际上,结构体在内存里面是存在对齐的,就像学校建宿舍,有的宿舍是住满的,有的却没有,但最开始建造的时候是不会因为某间宿舍没住满就建小,最后算大小的时候也是计算的所有宿舍能容纳的大小,而不是计算实际占据。

2.偏移量

因为并没有存满,所以对于真实情况的存储,假设一个起始位置,然后算每一个成员相对于偏移量的移动,可以确定到底哪个字节是有占用的

c语言标准库里提供了测量的宏

offsetof--->头文件stddef.h

测出对于s2这个结构体,一共浪费了六个字节,每个成员的偏移量为048

7.2对齐规则

1.结构体的第1个成员对齐到和结构体变量起始位置偏移量为0的地址处
2.从第2个成员变量开始,都要对齐到某个对齐数的整数倍的地址处。从第2个开始逐个考虑偏移量
对齐数------------------->编译器默认的一个对齐数与该成员变量大小的较小值,最小的“宿舍”是每个元素的对齐数的整除倍,比如1,4,8,就为4,1,8,8,就为8
VS中默认的值为8 ,Linux中gcc没有默认对齐数,对齐数就是成员自身的大小
3.结构体总大小为最大对齐数(结构体中每个成员变量都有一个对齐数,所有对齐数中最大的)的整数倍
4.如果嵌套了结构体的情况,嵌套的结构体成员对齐到自己的成员中最大对齐数的整数倍处,结构体的整体大小 就是所有最大对齐数(含嵌套结构体中成员的对齐数)的整数倍。

7.3对齐原因

1.不是所有的硬件平台都能访问任意地址上的任意数据,某些硬件平台只能在某些地址处取得特定数据

2.数据结构(尤其是栈)应该尽可能的在自然边界上对齐,原因是为了访问未对齐的内存,处理器要做两次内存访问,而对对齐的内存仅需访问一次

3.感悟:尽量把小的数据放一起,会比较节省空间和时间

7.4修改对齐数

#pragma pack(),可以设置默认对齐数,想设置多少就在括号里填写,一般是2的次方数

八.结构体实现位断

1.位断的声明和结构体是类似的,有两个不同,位断的成员必须是int, unsigned int ,signed int(char),还有就是位断的成员名后边有一个冒号和一个数字

如 int_a:2 int _b:5
2.数字表示这个成员要占的比特位的数量,但他依旧存在空间浪费,如图:

理论上A,47个比特位只要6个字节,但是算出来却是8个字节,所有掌握内存分配是很必然的
3.位断的内存分配

位断的空间是按照需求以4个字节或者1个字节来开辟的

因为16个比特位却占据了三个字节,就有以下问题:

一个字节(整型)的内存中,到底是从右向左占据,还是从左向右是不确定的

当剩下的空间不能满足下一个成员的时候,是否浪费不确定

在这里我们可以假设他是从右向左的,然后我们就可以假设不够的时候不占据了

-- - - -- - -。- - -- - - - - -。- - - -- - - - 。

假定是这样的,a是红色b是绿色c是蓝色d是橙色

我直接二话不说,先初始化为0,然后再赋值,

a赋值成10,在二进制位0000,1010,但a只有三个比特位,如果存储的话应该为010

b赋值成12,在二进制位0000,1100,b只有4个比特位,储存1100

此时对ab这个字节来说,他的二进制位为0110,0010就是62

同理换算c和d,应该为,03和04

结果应该就是620304(小彩蛋,这里有涉及大小端这个知识点,你会了没????????)

在内存窗口监视,果然是这样,说明假设很正确,得出如下结论:

一个字节(整型)的内存中,vs选择从右向左占据
当剩下的空间不能满足下一个成员的时候,vs选择浪费

此时可以很好的理解上面的例子为什么是8个字节了

4.位断影响因素很多,最好不要跨平台移植

a。刚才说到的从左向右还是从右向左

b。。是否浪费

c。。。int到底是有符号还是无符号

d。。。。int到底占据几个字节,16位是2个字节,32或64占4个字节

5.位断的应用

网络协议里,什么东西占多大是确定好的,这时候用位断是很OK的,节省了空间,传递也更快,学网络的时候才会深入学习这个
6.注意

位断里面几个成员共有一个字节,这样有的成员的起始地址不是某个字节的起始地址,那么这些位置处是没有地址的,内存中每一个字节分配一个地址,一个字节内部的bit位是没有地址的,所以不能对位断的成员使用&,就不能使用scanf进行输入,只能先输入放在一个变量里面,再赋值给位断

九.联合体

1.共用体(联合体):像结构体一样,联合体也是一个或者多个成员构成,这些成员可以是不同类型的

联合体的关键字是union,联合体的成员共用一块内存,编译器只为最大的成员分配足够空间

所以给联合体其中一个成员赋值,其他成员的值也随之改变

2.联合体的大小至少要能够保存最大的成员,当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍

联合体的成员之间不能同时使用,一定程度上节省了空间

3.联合体大部分其实和结构体是差不多的,以下讲解一个联合体的应用

场景:

要弄三种商品,每一种商品都有,库存量,价格,商品类型这三种和其他特定信息

图书:书名,作者,页数

杯子:创意设计

衣服:创意设计,颜色,尺寸

这时候设计为结构体,会有很多重复的东西浪费了空间,效率大大下降,联合体出来救场

如图:

4.联合体解决大小端判断

巧借共用的特点来设计代码,通过返回的值来判断大小端,强强强强!!!!

十.枚举

1.

enum,把可能的取值一一列举出来,

2.

{ } 里的是枚举类型的可能取值,也叫枚举常量,这些常量都是有值的,默认从0开始,依次增1,

也就是说,如果以%d的形式打印枚举括号里的第一个变量,他的值就是0

当然也可以在声明的时候给它赋值,比如a=1,这样第一个就变成1了

赋值后依旧往后递增1,且后面的值不可更改

3.有可能结合switch使用,比如曾经的计算器模拟,这时候case直接写add,他和case 0 是一样的,符合了switch的用法,又方便了阅读

枚举的代码可以调试

枚举常量是遵循作用域的,在函数内部的就只能在内部使用


http://www.jsqmd.com/news/891189/

相关文章:

  • Taotoken API Key管理与访问控制功能的使用感受
  • TypeScript类型体操构建AI修心智能体生成引擎——从2300+豆包智能体到七境宇宙的类型安全实践
  • 珠海夏令营推荐:军博营地海滨研学 - 19120507004
  • 实现自己的IOC容器——Winter (一)Bean加载
  • 3步解锁ThinkPad黑苹果:让T480笔记本完美运行macOS
  • AIfES:嵌入式AI框架解析与实战,实现MCU端完整训练
  • 英雄联盟智能助手:你的排位赛数据决策专家
  • 2026年国产在线ORP仪品牌TOP10权威排行榜:技术参数、市场表现与实战选型全解析 - 水质仪表品牌排行榜
  • Steam挂刀行情站:24小时自动化交易监控系统的完整技术实现指南
  • Linux 后台任务详解:、nohup、jobs、systemd 的区别
  • 《多智能体系统实战:我用10个智能体搭建了一个自动赚钱的AI公司》
  • 别再手动改时间了!用timedatectl一条命令搞定Linux时区与NTP同步(Ubuntu/CentOS通用)
  • 2026高口碑普拉提培训机构推荐:优质机构选择指南 - 品牌2025
  • JMeter接口测试中Cookie会话保持的七步实战法
  • 记录一次claude配置知乎mcp经历
  • 佛山黄金回收行业综合实力排名TOP5,2026年5月权威测评榜单 - 生活测评君
  • 简单好用!WinRAR的三种密码保护方式
  • av1编码--编码块的预测约束条件
  • 单图扩散模型实战:多尺度与提示学习实现精准图像编辑
  • 物理生物学研究报告【20260018】
  • Linux 环境变量详解:PATH、export、source 到底是什么?
  • CDR标准体系再添三件套:组网、业务、工程同步落地
  • 百度网盘下载加速终极指南:使用Python工具实现满速下载的完整教程
  • 如何利用组策略精准管控USB与可移动存储设备
  • 系统辨识选最小二乘还是最大似然?一个传感器噪声的例子讲明白
  • 从“飞起来”到“管得好”:2026工程进度低空管理系统供应商推荐 - 品牌2025
  • 3大智能特性重塑象棋辅助体验:视觉识别+实时分析+多平台适配
  • OpenCode + oh-my-openagent 实践全记录
  • 软件测试专栏(10/20):安全测试实战:OWASP Top 10漏洞检测与防护
  • 新鲜出炉!2026高级PDF编辑器推荐排行 专业实测榜单 - 极欧测评