结构体
结构体类型的创建(声明)
struct student{
char name[1024];
int age;
}; //分号必须有
结构体是否可以自引用了?
这样对么?
struct student{
char name[1024];
int age;
struct student node;
};
答:这样是不对的,如果这样则结构体所占字节数就无法确定了.
正确自引用应该创建一个结构体指针,这样结构体大小就可以确定,如下
struct student{
char name[1024];
int age;
struct student* node;
};
结构体变量的定义和初始化
结构体变量的定义
struct student a;
声明类型的同时,也定义了变量b
struct student{
char name[1024];
int age;
}a;
我们发现这样定义变量很麻烦,可不可以直接用student来定义变量了?
可以的
在创建结构体的同时利用typedef即可实现,如下
typedef struct student{
char name[1024];
int age;
}student; //之后就用此结构体来举例
结构体变量的初始化
定义变量的同时就可以初始化
student a={'小明',15};
结构体嵌套初始化
struct Node {
int data;
student p;
struct Node* next;
}n1 = {10, {4,5}, NULL};
结构体大小的计算(结构体内存对齐规则)(默认32位系统下)
int 占4字节,char占1个字节,指针占4字节,那么结构体所占字节就是所有类型所占字节的总和吗?
不是的.
结构体大小,遵循结构体内存对齐规则,有四条如下
1. 第一个成员在与结构体变量偏移量为0的地址处。 //即起始位置0
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值
VS中默认的值为8
Linux中没有默认值
3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
根据上述四条规则即可正确计算出结构体的大小.
如下结构体所占字节数?(默认vs下,假设起始地址为0)
struct S1 {
char c1; //1个字节,地址0
int i; //4个字节,8大于4,所以对齐数为4,所以i地址为从4开始,占4,5,6,7四个字节
char c2; //1个字节,1<8,所以对齐数为1,所以占地址8一个字节
//所以4+4+1=9,又因为9不是该结构体最大对齐数4的整数倍,所以该结构体占12字节
};
printf("%d\n", sizeof(struct S1)); //12
结构体内存对齐的优点:其虽然浪费了内存,但却换来了硬件上的方便,提高了内存访问效率
到这里可能就会有人想到,如果合理的安排结构体成员的顺序,在一定程度上是可以节省内存的
但是试想,如果只为了节省空间而将成员的顺序打乱了,代码的可读性将有可能大大降低,所以如何
排放结构体成员还是以代码可读性为优先前提较好,毕竟当前计算机内存足够使用
默认对齐数的修改(当默认对齐数不合适的时候我们可以自己修改)
在结构体之前加上
#pragma pack(8) //设置默认对齐数为8
结构体之后加上
#pragma pack()//还原默认对齐数
位段
有些情况如性别,只有男女两种情况,这是有一位二进制bit位(1或0)就足以表示,位段就可以实现
c语言在创建结构体的时候可以指定成员所占的二进制位数(bit),即为位段,位段成员名后有一个冒号和数字,
数字即为指定所占的二进制bit位,例如
struct A {
int _a:2; // 占2位(bit)
int _b:5;
int _c:10;
int _d:30;
};
位段的内存分配
1. 位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型
2. 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。
3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。
枚举
枚举就是一一列举
例如一周有七天可以一一列举
enum day{
Mon, //默认从0开始,一次递增1,当然在定义的时候也可以赋初值。
Tues,
Wed,
Thur,
Fri,
Sat,
Sun
}; //这就是枚举类型的定义
枚举的优点:
1. 增加代码的可读性和可维护性
2. 和#define定义的标识符比较枚举有类型检查,更加严谨。
3. 防止了命名污染(封装)
4. 便于调试
5. 使用方便,一次可以定义多个常量
联合(共用体)
联合体的特点:成员共用内存空间(所以它的大小至少为它的成员的最大值)
联合体的定义
union un{
int a;
char arr[10];
};
联合变量的定义
union un un1;
联合大小的计算
联合的大小至少是最大成员的大小。
当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。