结构体
1、谈谈你对结构体的理解。
答,首先在结构的基础知识上,结构是一些值的集合,这些值称为成员变量结构的每个成员可以是不同类型的变量。结构体其实就是把(一些单一类型的数据)不同类型的数据组合在一起的做法便于数据的管理和操作。它是属于自定义类型。而自定义类型我们又分为结构体枚举联合体。
2、如何创建结构体类型和创建结构体变量呢?
分条作答
(1)创建结构体类型:也叫做结构体的声明,需要使用struct的关键字。他是作为结构体的一个符号,或者说是一个标志,后面需要写结构体的名字,用大括号{},括起来,里面有不同的成员变量,最后用分号;来结束。
struct student
{char name[10];int age;int tel;};
(2)创建结构体变量:就是struct 结构体名字 变量名;比如 struct student u1; Struct就是结构体的标志,student就是结构体的名字,而u1就是变量名。
struct student u1;
(3)结构体的初始化:就是在创建结构体变量u1的同时进行了初始化。用大括号括起来,里面的内容就是对应结构体类型的成员变量进行赋值。比如
struct student u1={"zhangsan",20,123456};
3、结构体的访问是如何进行的呢?
- 当使用结构体对象的时候,使用点.来访问成员名。
- 如果结构体指针变量的话,用箭头->来访问。
4、结构体内存所占大小是多少?是如何计算的?结构体对齐规则是怎么样的?
(重点就是确定对齐数首位置放在那里)
1.第一个成员在:与结构体变量偏移量为0的地址处。
2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数=编译器默认的第一个对齐数与该成员大小的较小值。
Vs中默认的对齐数值是8。
3.结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
4.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
5、为什么要存在内存对齐呢?
(1)因为平台原因移植原因,不是所有的硬件平台都能访问任意地址上的任意数据的某些硬件平台只能在某些地址处取得某些特定类型的数据,否则抛出硬件异常。
(2)性能原因数据结构,尤其是栈,应该尽可能地在自然边界上对齐,原因在于为了访问未对齐的内存,处理器需要两次内存访问,而对齐的内存访问仅需要一次访问。总体来说,结构体的内存对齐就是拿空间来换取时间的做法。
6、那在设计结构体的时候我们需要既满足对齐又要节省空间,应该如何做到呢?
让占用空间小的成员尽量集中在一起。可以修改默认对齐数,使用#pragma这个预处理指令。
就是结构在对齐方式上不合适的时候,可以自己更改默认对齐数。比如 #pragma pack(1)
代表设置默认对齐数为1,这样结构体里面的变量相当于都是紧挨着一个一个放在内存中。
7、结构体传参是怎么样的呢?
答,在函数中,函数传参时,参数是需要压栈,会有时间和空间上的系统开销。如果传递一个结构体对象的时候,结构体过大。参数压栈的系统开销比较大,所以会导致性能的下降。
结论,结构体传参的时候要传结构体的地址。
8、位段是什么?
答,位段的声明和结构体的声明是类似的,有两个不同点:
(1)位段的成员必须是int 、unsigned int或signed int
(2)位段的成员名后面有一个冒号:和一个数字,后面这个数字表示占几位(bit),即占几个二进制bit位。这个数字不能大于32。位段就是为了节省空间。
9、位段的内存分配是怎么样的?
(1)位段的成员可以是int 、unsigned int、 signed int或者是char,属于整形家族的类型。
(2)位段的空间上是按照需要以四个字节或一个字节的方式来开辟的。
(3)位段涉及很多不确定因素,位段是不跨平台的。注重可移植的程序,应该避免使用位段,所以位段不支持跨平台
总结:位段和结构体相比,位段可以达到同样效果,可以节省很好空间,但是有跨平台问题存在。
位段的应用:在网络上传输数据的时候,为了让数据包更小些,对于数据包的分类,可能需要为段方式来描述。就像路上如果全是大卡车,可能会拥堵。但若是小汽车或者自行车就比较宽松,行驶的就会更快,效率高。(自己的理解哦!!!)
这里给些补充,关于位段的跨平台问题:
1.int位段被当成有符号数还是无符号数是不确定的
2.位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机器会出问题
3.位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
4.当一个结构包含两个位段,第二个位段成员比较大,无法容纳第一个位段剩余的位时,是舍弃剩余的位还是利用,这是不确定的。
枚举、共用体
1、枚举是什么?
所谓枚举,就是一一列举,把可能的取值一一列举出来。例如,生活中一周有七天,可以一一列举;性别有男、女、,可以一一列举;月份有12个月都可以举列出来,而这些值就可以定义为枚举类型,使用关键字enum,可以通过枚举创建变量,也可以在创建枚举时赋初始值。枚举里面可能的取值默认是从0开始的。
2、枚举的优点是什么?我们可以使用#define定义常量,为什么非要使用枚举呢?
(1)增加代码可读性和可维护性
(2)和#define定义的标识符比较,枚举具有类型,检查更加严谨。#define定义的是符号,是完全替换的,没有具体类型。
(3)防止了命名污染(便于封装),枚举可以把符号放在自己的范围内。
(4)便于调试
(5)使用方便,一次可以定义多个常量,但是define定义常量时每次都需要写#define,很繁琐。
3、联合也叫共用体,也叫联合体。它和结构体有什么区别?
先回答分别是什么,再说区别
(1)联合类型的定义:联合也是一种特殊的自定义类型。这种类型定义的变量也包含一系列成员,特征是这些成员共用同一块空间,所以联合也叫共用体。使用union关键字声明
联合的特点(在内存分配上):联合的成员是共同用一块内存空间的。这样一个联合变量的大小至少是最大成员的大小。因为联合至少得有能力保存最大的那个成员。
(2)结构体定义是一种用户自定义的复合数据类型,允许将多个不同类型的变量组合在一起,形成一个逻辑上的整体。结构体可以包含多个成员,每个成员可以是基本类型或其他结构体类型。他使用关键字是struct
结构体内存分配上:成员变量在内存上是各自占各自的空间。适用于每个成员都要独立存在的情况。
4、联合体大小的计算是什么?
(1)联合的大小至少是最大成员的大小。
(2)当最大成员大小不是 最大对齐数 的整数倍的时候,就要对齐到最大对齐数的整数倍。
对于这些问题的代码理解,大家可以参考如下分析,欢迎大家的反馈和建议哦!!!!
c语言--结构体精讲-CSDN博客
c语言--自定义数据类型--位段、枚举、联合_自定义数据段-CSDN博客