1. 结构体类型的声明
结构体是一些值的集合,这些被统称为成员变量,结构的每一个成员类型是可以不同类型的变量。
可以是标量,数组,指针甚至是其他结构体
描述一个学生
struct stu
{
char name[20];名字
int age;年龄
int sex[5];性别
char id[20];学号
};
1.1 结构体的初始化
按结构体的成员顺序初始化
struct stu s = {"张三", 18, "男", A1234567};
按指定结构体的成员初始化
struct stu s = {.name = "张三", .age = 20, .id = A1234567, .sex = "男"};
1.2 结构体成员访问操作符
结构体可以通过( . ),和 -> 俩个操作来访问
想要打印结构体指定成员,就可以直接用 . 操作符
struct stu
{
char name[20];名字
int age;年龄
int sex[5];性别
char id[20];学号
};
struct stu s = {"张三", 18, "男", A1234567};
printf("%s\n", s.name);
这样就可以直接打印出名字
要时有些时候我们直接接受的不是一个结构体,而是一个结构体指针那我们就需要用 -> 操作符来直接访问结构体的成员
struct stu
{
char name[20];名字
int age;年龄
int sex[5];性别
char id[20];学号
};
struct stu s = {"张三", 18, "男", A1234567};
struct stu *p = s;
printf("%s\n", p -> name);
当然结构体指针也是可以通过 . 操作符来访问成员的,只不过需要先解引用再用 . 操作符来访问
只不过这样有点多此一举了,因为 -> 操作符就是专门用来访问结构体指针成员的
1.3 结构的特殊声明
在声明结构的时候,可以不完全声明。
struct
{
char name[20];
int age;
}x;
这种被称为匿名结构体类型,这种类型如果没有对结构体重命名的话,基本只能使用一次。
1.4 结构体的自引用
结构体包含一个结构体本身是无穷大的,是不合理的,正确应该包含同类的指针。
struct st
{
int n;
sttuct st* next;
};
2. 结构体内存对齐
2.1 对齐规则
1. 结构体的第一个成员对齐到和结构体变量起始位置偏移量为0的地址处
2. 其他成员变量要对齐到对齐数的整数倍的地址处。
- 对齐数是编译器默认的一个对齐数与该成员变量大小的较小值。
- VS中默认的值是8
3. 结构体总大小为最大对齐数的整数倍
4.如果嵌套了结构体的情况,嵌套的结构体成员对齐到自己成员中最大对齐数的整数倍处,结构体大小就是所以最大对齐数的整数
俩个结构体里面的成员数量类型完全一样,只是存放顺序不一样,那他们大小是一样的吗
struct st st1
{
int a ;
char b;
char c;
};
struct st st2
{
char b;
int a;
char c;
}
printf("st1 = %zd", st1);
printf("st2 = %zd", st2);
运行程序
str1 = 8
str2 = 12;
struct st st1 在VS中默认值是8,对齐数是编译器和成员变量大小比较而取的较小值
{
int a ; int 大小为 4 ,VS 为8, 默认从偏移量为 0 的地址开始存储,存储4个字节大小
char b; char 大小为 1 ,对齐数是 1 要从对齐数的整数倍开始存储,从 5 开始存,
5 是 1 的整数倍存进去了
char c; 紧接着存 1 从 6 开始存刚好也是整数倍。
}; 结构体总大小为最大对齐数的整数倍, st1 最大对齐数是 4 结构体大小要取
4 的整数倍我们已经存了6个字节但是 6 不是 4 的整数倍,
那我们往大拿取个 8 ,8是4的俩倍。所以st1结构体大小为8个字节
struct st st2
{
char b; 一样从偏移量为 0 开始存 存了 1个字节,
int a; 这个要存 4 个字节但是 2 不是4 的整数倍,只能从 4 开始存 4 个字节
char c; 存为上个数后大小已经为 8 了 这里存 一个字节 为 9
};结构体总大小为最大对齐数的整数倍,st2 最大对齐数是 4,9 不是 4的整数倍,往上取 16 ,
所以 st2 大小为16
同样结构体包含一个结构体变量也是按照顺序来一个个存储
struct st1
{
int a; 4
char b; 1
};
struct st2
{
char a; 1
struct st s; 4
};
st2 先会存 1 然后开始存 st1 ,st1最大对齐数是 4 从 4 开始存,
存入一个int, st2现在大小为 8 了开始存char 大小为 9 。
结构体总大小为最大对齐数的整数倍
取最大对齐数的整数倍,包含在st2的str1 最大对齐数是 4 而。
st2 其他成员的对齐数最大只为1 ,所以str2最大对齐数取 4 现在大小为9
不是4的整数倍,取12,所以st2结构体大小为12.
2.2 为什么存在内存对齐
结构体的内存对齐是拿空间来换取时间的
我们在设计结构体的时候,要节省空间的话尽量让占用空间小的成员方一起。
#pragme 这个预处理指令,可以改变编译器的默认对齐数1
#pragma park(1)//设置默认对齐数为1
结构体在对齐方式不合适的时候,我们可以用这个更改默认对齐数。
3. 结构体传参
struct st st1
{
char name[10];
int age;
};
void pfst(struct st* p)
{
printf("%d\n", p -> age);
}
int main()
{
struct st st1 = {"LILI", 18};
pfst(&st1)
return 0;
函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销。
如果传递一个结构体对象的时候,结构体过大,参数压栈的系统开销比较大,所以会导致性能的下降。
结构体传参的时候,要传结构体的地址。