定义结构体类型,只能说明该类型的组成情况,并没有分配内存空间。只有当定义属于结构体类型的变量时,系统才会分配空间给该变量
。
结构体中不允许对结构体本身的递归定义,但是可以使用指针指向本类型
结构体变量可以在定义时进行初始化赋值
对结构体变量初始化时,应该将各成员所赋初值依照结构体类型说明中成员的顺序依次放在一对大括号中,不允许跳过前面的成员给后面的成员赋值
,但可以只给前面若干成员赋初值,后面未赋初值的成员中,数值型和字符型的数据,系统自动赋值零。
结构体的空间计算
struct 的空间计算遵循的2个原则:
1:整体空间是占用空间最大的成员(的类型)所占字节数的整数倍
,但是在32位Linix + gcc环境下,若最大成员类型所占字节数超过4,如double是8,则整体空间是4的倍数即可。
2:数据对齐原则。内存按结构体成员的先后顺序排列,当排到该成员变量时,其前面已摆放的空间大小必须是该成员类型大小的整数倍
,如果不够则补齐,依次向后类推。但在Linux + gcc环境下,某成员类型所占字节数超过4,如double是8,则前面已摆放的空间大小是4的整数倍即可,不够则补齐
看个例子方便理解:
struct Demo1
{
char a;
double b;
int c;
char d;
};
cout << sizeof(Demo1) << endl; // 24
偏移 | 0 | 8 | 16 | 20 | 21 |
---|---|---|---|---|---|
字节数 | a(占用字节1) | b(占用字节8)(8+8=16) | c(占用字节4)(16+4=20) | d(占用字节1)(20+1=21) | 剩余3字节空着 |
讲解 | a是char类型,占用1个字节 a放在偏移量为0的位置上 | b是double类型,占用8字节。 根据规则2,前面已摆放空间必须是8的整数倍,不够则补齐。 离 1 最近的地址是8,因此 b 放在偏移量为8的位置上 | c是int类型,占用4字节。 根据规则2,前面已摆放空间必须是4的整数倍 | d是char类型,占用1字节 | 根据规则1,总节数必须是8的倍数 现在总字节是21,最接近8的倍数的是24,因此最终字节数就是24 |
结构体中包含子结构体的空间计算
当结构体中含有结构体时,struct空间计算的原则应该修改为:
1:整体空间是子结构体与父结构体中占用空间最大的成员(的类型)所占字节数的整数倍
,但是在32位Linix + gcc环境下,若最大成员类型所占字节数超过4,如double是8,则整体空间是4的倍数即可。
2:数据对齐原则。父结构体内存按结构体成员的先后顺序排序,当排到子结构体成员时,其前面已摆放的空间大小必须是该子结构体成员中最大类型带大小的整数倍
,如果不够则补齐,依次向后类推。但在Linux + gcc环境下,某成员类型所占字节数超过4,如double是8,则前面已摆放的空间大小是4的整数倍即可,不够则补齐
看个例子方便理解:
struct Demo1
{
char c; // 偏移为0,占用字节 1
int i; // 根据规则2,前面占用空间需要是4的倍数,因此i在偏移量为4的位置上。占用字节4,4 + 4 = 8。总共是8字节
};
struct Demo2
{
char c1; // 偏移为0 ,占用字节1
Demo1 d; // 根据规则2,前面占用空间需要是子结构体重占用成员最大的倍数,因此需要是4的倍数,d在偏移量为4的位置,占用字节为8.4+8=12
char c2; // 偏移为12,占用字节1。12 + 1 = 13.根据规则1需要是4的倍数,16最接近13,因此占用的总字节数为16
};
cout << sizeof(Demo1) << endl; // 8
cout << sizeof(Demo2) << endl; // 16
结构体中包含数组的空间计算
在结构体中,数组是按照单个变量一个一个进行摆放的
,不是视为整体。
// 含有数组的结构体空间的计算
struct s1
{
char a[8]; // 偏移为0开始,占用字节1*8=8
int b; // 偏移为8开始,占用字节4.8 + 4 = 12
};
struct s2
{
char a; // 偏移为0开始,占用字节1
s1 s; // 偏移为4开始,(根据规则2,前面所占内容需要是4的倍数),占用字节12。总子节数 = 12 + 4 = 16
};
struct s3
{
s2 s; // 偏移为0开始,占用字节16
char c; // 偏移16开始,占用字节1。16 + 1 = 17。根据规则1,需要是整数倍,需要是int即4的整数倍,所以总子节为20
};
cout << sizeof(s1) << endl; // 12
cout << sizeof(s2) << endl; // 16
cout << sizeof(s3) << endl; // 20