c语言:结构体(详解)

初识结构体

  • 一.结构体声明
    • 1.结构体的概念
    • 2.声明
  • 二.结构体的基础使用
  • 三.结构体变量的定义和初始化
  • 四.空结构体
  • 五.柔性数组
    • 1.定义
    • 2.使用
  • 六.结构体内存对齐
  • 七.位端

在这里插入图片描述

一.结构体声明

1.结构体的概念

结构体是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量

这里与数组做出区分:数组是一组相同类型元素的集合

结构体主要是用来描述复杂对象,比如一本书,我们需要描述它的内容,作者名,售价…很明显只用int char…类型是不行的

2.声明

在这里插入图片描述

至于variable-list是什么请看下文结构体的基础使用

例子:我需要描述一个学生

在这里插入图片描述

二.结构体的基础使用

在这里插入图片描述

注意结构体的声明只是定义了该结构体的类型(这类型就像是int ,char…是结构体被定义的类型),而s1,s2,s3才是向计算机申请了一块空间

在这里插入图片描述

而创建的变量才开辟空间

在这里插入图片描述

这里看看variable-list是什么

在这里插入图片描述

s1,s2,s3和s4,s5的区别就像是定义一个全局变量i和一个局部变量i的区别

结构体的成员可以是变量,字符,数组甚至是其他结构体

三.结构体变量的定义和初始化

在这里插入图片描述

定义其实很简单,一般有三种方法,其中s4,s5,s6是全局变量,s1,s2,s3是局部变量

接下来初始化结构体变量
在这里插入图片描述

这里注意括号内的元素要一一与声明内的相对应

那接下来将它打印出来

在这里插入图片描述

在这里插入图片描述

这里打印也是需要依次对应的,.操作符就是专门访问结构体

接下来使用指针打印

在这里插入图片描述
在这里插入图片描述

这里的道理其实是一样的传的是s1的地址那么*s1就是s1,然后再用.操作符。

其实这样写有些麻烦,所以c语言有->符号专门访问这种传址调用

在这里插入图片描述

四.空结构体

在这里插入图片描述在这里插入图片描述在这里插入图片描述

结论是结构体有多大和平台有关系,接下来来讨论一下空结构体有多大

在这里插入图片描述

这里可以看出在VS里,空结构体是不能被定义的(如果是c++项目是可以编过的),它要求至少有一个成员。那么在Linux环境下呢?

在这里插入图片描述

在这里插入图片描述

可以看出,在Linux环境里空结构体是直接编过了并且大小是0.那么我此时就有些好奇了,空结构体能不能定义变量呢?该变量的大小是多少呢?

在这里插入图片描述

在这里插入图片描述

我们发现空结构体可以定义变量并且该变量的大小是0。那既然空间是0,可不可以存储数据呢?答案是不行的

在这里插入图片描述
在这里插入图片描述

换言之,在c语言中可以定义一个大小为0的变量,但是因为该变量没有空间,所以不能赋值并且不同的编译器对空结构体的要求不一样,要从多种环境下看

五.柔性数组

1.定义

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

柔性数组不同于变长数组,它只能被定义在结构体中

对于c语言是不能定义一个大小为0的数组的

在这里插入图片描述

但对柔性数组来说,我们一般将它的大小填为0并且编译器是能编过的

在这里插入图片描述
其实以上就是一个柔性数组的定义,但根据我们习惯,我们尽量把柔性数组放在最后定义,也就是如下

在这里插入图片描述

2.使用

首先要明确的是柔性数组不占空间

在这里插入图片描述

柔性数组就是帮助我们开辟空间的

在这里插入图片描述

在这里插入图片描述

其实严格意思上讲,柔性数组就是将结构体变长

在这里插入图片描述

六.结构体内存对齐

看一个例子

在这里插入图片描述

两个结构体我们只是调整了顺序但是它们的内存大小却截然不同,这就是因为内存对齐。

1.结构体的第一个成员,对齐到结构体在内存中存放位置的0偏移处。

在这里插入图片描述

c1存到偏移量0位置。

2.从第二个成员开始,每个成员都要对齐到对齐数的整数倍数。

对齐数是结构体成员自身大小和默认对齐数的较小数。在VS里,默认对齐数是8;在Linux里没有默认对齐数。

接下来存放i,i自身大小是4而VS的默认对齐数是8,4<8,按照4来对齐。偏移量必须是对齐数的倍数,也就是说i必须从偏移量为4的位置开始储存。

在这里插入图片描述

接下来c2的分析方法与i一样。

在这里插入图片描述

3.结构体的总大小必须是所有成员对齐数中最大的对齐数的整数倍。

这里最大对齐数是4,那么它的总大小应该是4的倍数,而上面一个9个字节很明显不是4的倍数,所有得继续向下走。

在这里插入图片描述

所以stu1的总大小就是12。同理stu1按照这么分析就是8.

再来一个例子

在这里插入图片描述
在这里插入图片描述

此时在结构体内包含另一个结构体又有新的规则。

4.如果结构体内嵌套结构体,里面的结构体要对其自己最大成员的整数倍。

s3的大小是16(这里不再计算了),而s3里最大对齐数是8,所以s3应该对齐8的整数倍。

在这里插入图片描述

接下来就是放d。

在这里插入图片描述

从0到31一共32个字节,判断是否为最大对齐数的整数倍(要包含嵌套结构体里的最大对齐数,8)。可以发现最大对齐数是8,而32是8的倍数,所以32就是s4的大小。

为什么要进行结构对齐呢?

在这里插入图片描述

下面是内存不对齐情况,a必须读取两次,但在上面内存对齐下,a只需要读取一次就可以了。注意这里内存一次读取多少字节却决于机器。

在这里插入图片描述在这里插入图片描述

自定义默认对齐数

上面说到,在VS里,默认对齐数是8.但有些时候这种默认对齐数可能并不合适,所以c语言又提供了一种宏#pragma pack来自定义对齐数。

在这里插入图片描述
在这里插入图片描述

#pragma pack(1),就是将默认对齐数改为1。而下面的#pragma pack()就是取消修改。意思是4这个修改的对齐数到#pragma pack就结束了。

七.位端

位段的声明和结构是类似的,有两个不同:
1.位段的成员必须是 int、unsigned int 或signed int(char也可以,因为char本质上也是整形) 。
2.位段的成员名后边有一个冒号和一个数字。

在这里插入图片描述
在这里插入图片描述

位端中的位其实就是比特位。一个整形应该是4个字节,32个比特位。我们看_a后面的2就代表它需要2给比特位,同理_b需要5个比特位,_c需要10个比特位,_d需要30个比特位。总共需要47个比特位,很明显只有两个整形才能装下,故该结构体的大小是8个字节。(位段本身设计就是为了节省空间,所以不用对齐)

内存分配方式

1. 位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型
2. 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。
3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。
4. 以上面的例子为例,a+b+c为17个比特位,那么一个整形还剩下15个比特位。下面的d需要30个比特位很明显装不下,需要在开辟一个整形空间,但它究竟是会将剩下的15个比特位占满还是直接从新的空间里开辟,c语言没有明确规定,取决于编译器。

在这里插入图片描述

位段的跨平台性

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

总结:
跟结构相比,位段可以达到同样的效果,但是可以很好的节省空间,但是有跨平台的问题存在。

在这里插入图片描述文章来源地址https://uudwc.com/A/b1yXP

原文地址:https://blog.csdn.net/m0_73790767/article/details/128013188

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请联系站长进行投诉反馈,一经查实,立即删除!

上一篇 2023年09月26日 13:22
【Git】GitHub 的两种 URL 及其身份验证
下一篇 2023年09月26日 13:22