文章目录
每日一言
Develop your imagination – you can use it to create in your mind what you hope to create in your life.
发展你的想像力 – 你可以用它在心里创造你想在现实生活创造的东西。
结构体是什么?
结构体是一种自定义的数据类型,可以包含多个不同类型的数据成员,并可以根据这些成员进行组合和访问。结构体可以用于表示一个具有多个属性的实体或对象,例如一个人的姓名、年龄和性别,一个车辆的品牌、型号和颜色,等等。
为什么要使用结构体?
C语言已经为我们提供了许多的内置类型,如:int、long、float、double、char、short等,但这些类型只能描述相对单一的事物。
假如我要描述一个人,人是一个相对复杂的事物,他有姓名、年龄、性别、身份证号、体重、电话号码等属性。这时如果只用上面给出的类型是很难描述一个人的所有信息的。
如何使用结构体?
结构体的定义
struct 结构体名称 {
数据类型 变量名1;
数据类型 变量名2;
// ...
};
例如用结构体描述一个人:
struct Person {
char name[20];//名字
int age;//年龄
char gender;//性别
char id_card[18];//身份证号
float weight;//体重
char phone[11];//电话
};
结构体的声明
声明结构体变量的格式如下:
struct 结构体名 变量名;
例如,声明一个名为awa,年龄为18岁,性别为男,身份证号为666666,体重为60.2,电话为1234567的人:
方式一
声明结构体变量时直接定义结构体
代码如下:
struct Person {
char name[20];//名字
int age;//年龄
char gender;//性别
char id_card[18];//身份证号
float weight;//体重
char phone[11];//电话
}awa = {"awa",18,'M',"666666",60.2,"1234567"};
方式二
先定义结构体类型,再声明结构体变量
代码如下:
struct Person {
char name[20];//名字
int age;//年龄
char gender;//性别
char id_card[18];//身份证号
float weight;//体重
char phone[11];//电话
};
struct Person awa = {"awa",18,'M',"666666",60.2,"1234567"};
两种方式的本质区别在于第一种方式在定义结构体变量的同时也定义了结构体类型,而第二种方式分别定义了结构体类型和结构体变量。而在实际应用中,通常会使用第一种方式,代码会更加简洁明了。 C语言也支持在结构体中嵌套定义其他结构体。
如何访问结构体中的成员
我们依然以上面的awa为例,如何在屏幕上打印出awa的电话呢?
我们有两种方法:
法一:
通过点操作符来访问结构体成员。
代码如下:
printf("awa的电话是:%s\n", awa.phone);
法二:
通过指针操作符来访问结构体成员。
代码如下:
struct Person *p;//定义一个指针p,它的类型是struct Person。
p = &awa;//将p指向结构体变量awa的地址。
printf("awa的电话是:%s\n", p->phone);
结构体内存对齐
现在我们对结构体有了大致的了解,接下来我们来谈一谈结构体是如何在内存中存储的。只有了解了它的本质,我们用起来就更加得心应手。
什么是结构体内存对齐
内存对齐是指将数据存储在内存中时,按照某种规则对其进行填充,使其在访问时的速度更快。这主要是因为CPU的读取速度与地址对齐有关。
对齐规则
- 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处
- 对齐数 = 编译器默认的一个数与该成员变量大小的较小值
- 结构体总是大小为最大对齐数的整数倍
- 如果是嵌套了结构体的情况,嵌套的结构体成员对齐到自己的成员中最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体中成员的对齐数)的整数倍
例:
求AA_t 所站的字节大小(假如编译器默认对齐数为8字节)
typedef struct{
int a;
char b;
short c;
short d;
}AA_t;
计算过程:
注意:
VS中默认的对齐数为8
Linux中gcc没有默认对齐数,对齐数就是成员自身的大小
修改默认对齐数
#pragma 这个预处理指令可以改变编译器的默认对齐数
例:
#pragma pack(1)
设置默认对齐数为1
#pragma pack()
取消设置的默认对齐数
一般不建议修改默认对齐数,它会导致许多问题。
1.可能会破坏结构体的内存对齐,导致结构体成员的访问速度变慢,因为不是按照CPU的最佳对齐方式进行的。
2.可能会增加内存的浪费。如果对齐数太小,内存对齐不足,会导致内存浪费,因为需要加入一些填充字节来填充对齐差距。
3.可能会影响平台的可移植性。不同的平台对内存对齐的要求可能不同,因此在不同的平台上运行代码时可能会出现错误或不一致的结果。
4.可能会使代码变得难以维护,并且会增加调试难度。更改默认对齐数通常是非标准的做法,开发人员可能需要花费更多时间来解决由此引起的问题。
为什么存在结构对齐
通过对结构体进行对齐,可以保证每个结构体成员访问时都能够在一个内存块中连续访问,提高了代码的执行效率。同时,结构体对齐也能够减少内存碎片的产生,进一步提高内存的利用效率。
注意:
内存对齐可以提高数据访问的效率,但同时也会增加内存空间的浪费。因此,在设计结构体时,需要权衡对齐对空间利用率和访问效率的影响,以达到最优的设计。
通常我们尽量让占用空间小的成员集中在一起
总结
- 结构体的定义:需要使用关键字struct,语法格式如下:
struct 结构体名称 {
数据类型 变量名1;
数据类型 变量名2;
// ...
};
-
成员变量的定义:可以是基本数据类型、指针类型、数组类型等。定义时需要指明变量名和数据类型。
-
结构体的大小:结构体的大小是所有成员变量大小的累加,需要考虑对齐方式和填充字节。
-
结构体的初始化:可以采用两种方式进行初始化,一种是在定义时赋值,另一种是通过赋值运算符对结构体对象进行初始化。
-
结构体的成员访问:可以通过".“或”->“运算符进行成员访问,”.“用于访问结构体对象的成员,”->"用于访问指向结构体的指针的成员。
-
结构体的传参:可以将结构体作为函数参数传递,可以通过传值或传指针的方式进行传参。
-
结构体的对齐方式:需要指明对齐方式,可以通过#pragma pack指令或__attribute__((packed))关键字来进行设置。
结语
请给自己些耐心,一口吃不成胖子。
山外青山楼外楼,莫把百尺当尽头。
保持空杯心态加油努力吧!
都看到这里啦!真棒(*^▽^*)
可以给作者一个免费的赞赞吗,这将会鼓励我继续创作,谢谢大家
编程小白写作,如有纰漏或错误,欢迎指正