大家好,今天和大家分享C语言结构体有关的知识,感谢大家观阅,记得三连支持一下哦!
一、结构体的概念
我们知道在C语言中有许多的内置类型,如int、char、float等等,但是仅仅只有这些内置类型是完全不够的我们所有问题的,比如:描述⼀个学⽣需要名字、年龄、学号、⾝⾼、体重等。C语⾔为了解决这个问题,增加了结构体这种⾃定义的数据类型,让程序员可以⾃⼰创造适合的类型。
二、结构的声明
假如我们要声明一个描述学生的结构体变量:
显然这个结构体有4个成员。通常结构体的声明在main函数的外面,也就是在全局中。
结构的特殊声明:
我们在声明结构的时候,可以不完全的声明。
如:
这种结构体只能使用一次被叫做——匿名结构体。
注意:
typedef 对结构体类型重命名:
结构体在声明完之后,我们用起来每次都要在前面加struct,这就十分的麻烦,有什么办法把它的变的和普通类型一样用的方便呢?typedef。如:
这样我们就可以使用简短的名字了。并且对匿名结构体进行重命名,匿名结构体就可以使用多次了。
三、结构体变量的定义和初始化
1.结构体变量的定义
结构体变量的创建其实和普通变量的定义是一样的。
如:
与普通变量不同的是要在前面加一个struct。
2.结构体变量的初始化
结构体变量的初始化有点类似于数组,我们直接来看例子:
这种方法是按照结构体成员一个一个进行初始化的。
这种方法是不按照顺序来初始化的。
四、结构的⾃引⽤
结构的⾃引⽤,顾名思义就是,结构体成员中包含结构体类型。
比如我们定义一个链表的节点:
我们可以看到上面的代码是错误的那是为什么呢?
其实,我们在声明这个结构体到next时,并没有完全声明完,⼀个结构体中再包含⼀个同类型的结构体变量,这样结构体变量的⼤⼩就会⽆穷的⼤,是不合理的,所以这里报了错。
正确的是要改成指针的形式,如:
在结构体⾃引⽤使⽤的过程中,夹杂了 typedef 对匿名结构体类型重命名,也容易引⼊问题,如:
我们可以看到这里出现错误。因为Node是对前⾯的结构体类型的重命名产⽣的,但是在结构体内部提前使⽤Node类型来创建成员变量,这是不⾏的。所以在结构体中自引用中我们要写完整。(包括匿名结构体中)。
五、结构体内存对⻬
我们知道内置类型是有大小的如:int大小是4个字节。那么结构体大小是多少呢?
我们可以看到结构体也是有大小的,但是我们发现上面两个结构体成员是一样的,只是顺序不一样,大小却不一样,这是为什么呢?这是因为结构体大小是要计算的,下面我们就介绍如何计算结构体的大小.
1.对⻬规则
在学习如何计算结构体的大小之前我们需要了解一个知识——结构体内存对⻬规则
下面我们看一些例子:
上面就是结构体A和结构体B大小不一样的原因。下面我们再来看一下难一点的:
我们可以看到这是一个结构体嵌套的类型,那么它的大小怎么求呢?我们来看:
好了以上就是结构体大小的计算方式了,为什么要这样计算呢?
2.为什么存在内存对⻬?
大多数解释有两个原因:
总的来说:就是拿空间来换取时间的做法。
所以我们在设计结构体的时候让占⽤空间⼩的成员尽量集中在⼀起,这样就既满⾜对⻬,⼜节省空间了。就如上面两个结构体A和B一样。
3.修改默认对⻬数
默认对齐数也是可以修改的。#pragma 这个预处理指令,可以改变编译器的默认对⻬数。
如:
如果我们将默认对齐数改为1,那么该结构体大小就是两个char类型和一个int类型,一共是6个字节。
六、结构体传参
我们可以看到上面结构体传参有传值和传址,那么它们哪一个好呢?这里优先推荐传址
因为:
所以:结构体传参的时候,要传结构体的地址。
七、结构体实现位段
下面我们来了解一下结构体实现位段的能力。
1.什么是位段
通俗来讲,位段就是改变了成员变量大小的结构体。
位段的声明和结构是类似的,有两个不同:
1. 位段的成员必须是 int、unsigned int 或signed int ,在C99中位段成员的类型也可以选择其他类型。
2. 位段的成员名后边有⼀个冒号和⼀个数字
如:
上面A就是一个位段类型,里面的成员大小被改变了。在这里是直接改成比特位而不是字节。下面我们来看看这个位段的大小。
我们可以看到是4个字节。那么位段在内存中是怎么存储的呢?下面我们就要讲讲位段的内存分配了.
2.位段的内存分配
前面我们提到位段成员是按比特位来存储的,由于在不同的编译器是存储的方式不同,所以位段的存储方式不同。如:
下面我们就来看看在VS环境下位段是怎样存储的。
我们可以看到在VS环境中确实是按照我们假设的这样来存储位段的,但是在其他环境下就不一定是这样了
3.位段的跨平台问题
位段的移植性是很差的。
所以:跟结构相⽐,位段可以达到同样的效果,并且可以很好的节省空间,但是有跨平台的问题存在。
位段使用注意事项:
好了以上就是本篇文章的全部内容了,感谢大家的观看,创作不易,三连支持一下吧!