1.结构体的声明:
1.1格式
struct struct_name
{
member_list;
}variable_list;
variable_list (声明全局结构体变量):可写可不写,一般少用(封装)
例子:
struct student
{
char name[20];
char id[20];
int age;
};
1.2其他方式
//匿名结构体----
struct
{
int a;
int b;
char c;
}s1; //----------匿名结构体必须带有variable_list,访问时只有通过该变量
struct
{
int a;
int b;
char c;
}* s2;
int main(void)
{
s2 = &s1; //此处在编译阶段会报错,因为 s1与&s2类型不一致,可看出,相同成员的匿名结构体
//不一样
return 0;
}
--------------------------------------------------------------------------------
//类型重定义
typedef struct Node
{
int a;
int b;
char c;
}Node; //---------------当typedef重定义结构体类型时,此时该位置为重定义后的类型名
int main(void)
{
//以下两种方式均可
struct Node s1;
Node s2;
return 0;
}
2.结构体的自引用
// 1.结构体的成员为自身类型的变量
struct Node
{
int a;
struct Node b; //此时算不出该结构体的大小,故该方法错误;
};
//2.结构体的成员为自身类型的指针变量
struct Node
{
int a;
struct Node* b; //此时大小是固定值
};
//上述也可以使用typedef
typedef struct Node
{
int a;
struct Node* b; //此时没有重定义后的类型所以不能用Node* b;
}Node;
3.结构体变量的定义以及初始化
3.1全局变量
struct stu
{
char name[20];
int age;
char id[20];
}s1, s2 = {"xiaoming", 20, "10002"};
struct str s3 = {"ia", 14, "13431"};
int main(void)
{
return 0;
}
3.2局部变量
struct stu
{
char name[20];
int age;
char id[20];
};
int main(void)
{
struct stu s3 = {"xiaoguan", "18", "42341"}; //默认顺序初始化
struct stu s4 = {.age=18, .name="xiaoguan", .id="41234"}; //指定顺序初始化
return 0;
}
4.结构体大小计算
4.1内存对齐
规则:
- 结构体第一个成员对于起始位置的偏移量为0
- 其余成员对齐到偏移量为对齐数的整数倍处 (对齐数,默认对齐数与自身大小的较小值,vs-8,linux-没有)
- 最后结构体的大小要为最大对齐数的整数倍
- 发生结构体嵌套,结构体的对齐数为其成员的最大对齐数
4.2题目
struct s1
{
char c1;
char c2;
int i;
}; //--- 大小为:8
----------------------------
struct s2
{
char c1;
int i;
char c2;
}; //--- 大小为:12
----------------------------
struct s3
{
double d;
char c;
int i;
}; //--- 大小为:16
----------------------------
struct s4
{
char c1;
struct s3 stu;
double d;
}; //--- 大小为:32
//------总结:尽量将字节小的成员放到一起,可以节约空间
4.3内存对齐的原因
- 为了可移植性:有些硬件平台不能访问任意地址上的数据,
- 性能原因:为了访问未对齐的内存,处理器要两个内存访问;而对齐的内存仅要一次
- 总结:结构体内存对齐是以空间换时间
4.4修改默认对齐数方法
方式#pragma pack(4)
取消方法:#pragma pack()
4.5结构体作为参数
- 结构体传参传地址,传值会导致参数压栈,消耗性能