1.结构体类型的声明
2.结构体变量的创建和初始化
3.结构体变量的赋值
4.结构体成员访问操作符
5.结构体内存对齐
1.结构体类型的声明
1.1结构体声明
struct 结构体名称
{
结构体成员...
}
举例:描述一个学生:
2结构体变量的创建和初始化
2.1匿名结构体类型
匿名结构体就是在声明时不给结构体取名字,这样的类型只能在结构体声明时顺便创建变量,在不使用关键字typedef时是不能在其他地方进行结构体变量的定义的。
这里对a的初始化不是必须的, 可以只定义结构体变量a。
2.2匿名结构体搭配typedef
这时候就可以用typedef所创造的别名实现结构体变量的定义了。
2.3结构体的自引用
在结构体中不能包含类型为自己本生的成员
在struct stu类型里放着一个struct stu类型的成员b,那么成员b里面又有一个类型为struct stu的成员变量,如此下去,就像套娃一样,永远走不到尽头。(结构体变量是可以不完全初始化的,这里不是因为未初始化成员变量b所导致的错误)
但是,结构体声明中允许有自身类型所对应的指针类型的成员变量。
那么,这里可以用匿名结构体吗?
答案是不可以的!!!
我们用typedef试试:
这是因为声明的优先级高于typedef,这里的stu是对前面这个结构体声明的取别名。
所以,最好是把名字取好。
3.结构体变量的赋值
使用花括号依次赋值
4.结构体成员访问操作符
方法一:用点号对结构体变量的成员变量进行访问。
方法二:用->通过结构体变量的指针对结构体变量的成员进行访问。
5.结构体内存对齐
5.1对齐规则
1.结构体的第一个成员对齐到结构体变量起始位置偏移量为0的位置
2.其他成员要对齐到对齐数的整数倍的地址处
对齐数=编译器默认对齐数和成员变量中较小的一个
vs的默认对齐数是8
linux中gcc没有默认对齐数,对齐数就是成员自身的大小
3.结构体总大小为最大对齐数(每个成员都有一个对齐数,取当中最大的)的整数倍
4.如果结构体1内嵌套了结构体2,那么结构体2的对齐数是结构体2成员变量中最大的对齐数,结构体1的总大小是所有最大对齐数(包含被嵌套的结构体成员)的整数倍。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
struct stu
{
char c1;
int i;
char c2;
};
int main()
{
printf("%zd", sizeof(struct stu));
return 0;
}
c1的大小是1,默认对齐数是8,所以c1的对齐数是1,现占用1字节
i的大小是4,默认对齐数是8,所以i的对齐数是4,为了对齐,先浪费3个字节,再分配4个字节,现占用8字节
c2的大小是1,默认对齐数是8,所以c1的对齐数是1,已经对齐,不需要浪费空间,分配一个字节,现在占用9字节
最大对齐数为4,为了对齐,需再浪费3个空间,共12字节
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
struct stu
{
char c1;
char c2;
int i;
};
int main()
{
printf("%zd", sizeof(struct stu));
return 0;
}
8个字节
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
struct stu
{
double d;
char c;
int i;
};
int main()
{
printf("%zd", sizeof(struct stu));
return 0;
}
16个字节
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
struct stu
{
double d;
char c;
int i;
};
struct s
{
char c1;
struct stu a;
double d;
};
int main()
{
printf("%zd", sizeof(struct s));
return 0;
}
32个字节
5.2为什么存在内存对齐
1.不是所有硬件都能任意访问任意地址上的任意数据的,某些硬件只能在某些地址处取某些特定类型的数据。
2.对齐后的数据基本只需一次就能完成访问,假设处理器一次取8个字节,则开始取的位置必须是8的整数倍,如果能保证所有的double类型的数据地址都对齐到8的整数倍,那么这样的double类型的数据只需一次就能取出。
总的来说:内存对齐是一种空间换时间的操作
在声明结构体的时候,尽量让小的成员聚在一起,从而使用零碎的空间,在节省时间的前提下,尽量节省空间。
5.3修改默认对齐数
#pragma pack()//括号里写新的默认对齐数
#pragma pack()//括号里什么都不写,恢复默认对齐数