■结构体
◆结构体声明
struct tag
{
member_list;
}variable_list;
例如定义一个学生的信息
struct Stu
{
char name[20];//姓名
int age;//年龄
char sex[5];//性别
char id[20];//学号
};//这里的分号不可以丢,是语法规定
◆特殊声明
在声明结构的时候,可以不完全声明
struct
{
int a ;
char b;
float c;
}x;
struct
{
int a;
char b;
folat c;
}a[20],*p;
以上两个结构体在声明的时候忽略了结构体标签(tag)
问:在上面代码的基础上,
p=&x;
合理吗?
答案当然是不合理的,编译器会把上面的两个声明当初完全不同的两个类型,所以是非法的。
◆结构体自引用
struct Node
{
int data;
struct Node next;
};
以上代码是否可行,如果可以,那么sizeof(struct Node)是多少?
答案当然是不行的,编译显示错误,这种方式是结构体里面套了结构体,无限的嵌套循环。分配内存时根本无法确定结构体的长度,所以非法。在这种情况下,应该使用指针来完成嵌套,原因是因为在系统中指针的长度是确定的。
正确的自引用方式如下
struct Node
{
int data;
struct Node* next;
};
◆结构体内存对齐
☆计算结构体的大小
结构体的对齐规则:
①第一个成员在与结构体变量偏移量为0的地址处
②其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处
对齐数=编译器默认的第一个对齐数 与 该成员大小的较小值
vs中默认的对齐数为8
③结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍
④如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
存在内存对齐的原因
结构体的内存对齐是用空间来换取时间的做法,那么在设计结构体的时候,我们既要满足对齐,又要节省空间,就尽量让占用空间小的成员集中在一起
修改默认对齐数
结构在对齐方式不合适的时候,我们可以自己更改默认对齐数
可以使用#pragma这个预处理指令
#pragma pack(4)//设置默认对齐数为8
#pragma pack()//取消设置的默认对齐数,还原为默认
◆结构体传参
举一个例子
struct S
{
int data[1000];
int num;
};
struct S s={{1,2,3,4},100};
//结构体传参
void print1(struct S s)
{
printf("%d\n",s.num);
}
//结构体地址传参
void print2(struct S* s)
{
printf("%d\n",ps->num);
}
int main()
{
print1(s);//传结构体
print2(&s);//传地址
return 0;
}
问:print1和print2函数哪个好?
答案首选print2。因为函数在传参的时候,参数是需要压栈的,会有时间和空间上的系统开销。如果传递一个结构体对象的时候,结构体过大,参数压栈的系统开销比较大,所以会导致性能的下降。因此在结构体传参的时候,要选择结构的地址传参
■位段
◆位段的声明
①位段的成员必须是 int、unsigned int 或 signed int。
②位段的成员名后面必须有一个冒号和一个数字。
举个例子
struct A
{
int a:2;
int b:5;
int c:10;
int d:30;
};
A就是一个位段类型。冒号后的数字表示该数据分配了几个比特位。
举例计算位段的大小
struct S
{
char a:3;
char b:4;
char c:5;
char d:4;
};
struct S s={0};
s.a=10;
s.b=12;
s.c=3;
s.d=4;
大小为 3个字节
◆位段的内存分配
①位段的成员可以是 int、unsigned int 或 signed int 或者是char(属于整形家族)类型。
②位段的空间上是以4个字节(int)或者一个字节(char)的方式来开辟的
③位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。
■枚举
枚举也就是列举
◆枚举的定义
enum Color
{
RED,
GREEN,
BLUE
};
以上定义的 enum Color 就是枚举类型。{ }中的内容是枚举类型的可能取值,也叫做枚举常量。
这些值都是有值的,默认从0开始,一次递增1,也可以在自定义的时候赋初值。
◆枚举的优点
①增加代码的可读性和可维护性
②和#define定义的标识符比较枚举有类型检查,更严谨
③防止了命名污染
④便于调试
⑤使用方便,一次可以定义多个常量
■联合(共用体)
◆定义:
联合也是一种特殊的自定义类型,这种类型定义的变量也包含一系列的成员,特征是这些成员公用一块空间(所以也叫做共用体)例如:
//联合体类型声明
union Un
{
char c;
int i;
}
//联合变量的定义
union Un un;
;
计算这个联合体的大小
结果为4个字节
◆联合体的特点
联合体的成员是共用一块内存空间的,这样一个联合体的大小,至上是最大成员的大小(因为联合至少得有能力保存那个最大的成员)。
◆联合大小的计算
联合的大小至少是最大成员的大小
当前最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。