一、结构体
1.结构体的声明
- 结构体是一些值的集合,这些值被称为成员变量
- 结构体的每一个成员可以是不同的类型变量
struct Stu
{
char name[20];
int age;
char sex[5];
char id[20];
};
2.结构体内部成员的访问
- 结构体.成员名
- 结构体指针->成员名
struct Stu stu;//定义结构体变量stu
stu.age = 20;//.访问结构体成员
struct Stu * pstu = &stu;
pstu->age = 18;//结构体指针访问结构体成员
其中->访问结构体变量相当于 先解引用再. 的操作。
3.结构体的自引用
struct Node
{
int data;
struct Node* next;
};
4.结构体变量的定义和初始化
struct Stu
{
char name[20];
int age;
}p1;//声明类型的同时定义变p1
struct Stu p2;//定义结构体变p2
struct Stu p3 = {"zhangsan",15};//初始化:定义变量的同时赋初值
//结构体嵌套初始化
struct Node
{
int data;
struct Stu p;
struct Node* next;
}n = { 10,{"zahngsan",19} ,NULL};
struct Node n2 = { 10, { "zahngsan", 19 }, NULL };
5.内存对齐
结构体的内存对齐规则:
1.第一个成员在与结构体变量偏移量为0的地址处
2.其他成员变量要对齐到某个数字的整数倍的地址处
对齐数=编译器默认的一个对齐数与该成员大小的较小值
3.结构体总大小为最大对齐数的整数倍。
4.如嵌套其他结构体,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(包括嵌套的结构体)的整数倍
struct s1
{
char c1;
int i;
char c2;
};
printf("%d\n", sizeof(struct s1));//12
struct s2
{
char c1;
char c2;
int i;
};
printf("%d\n", sizeof(struct s2));//8
struct s3
{
char c1;
struct s3 c2;
int i;
};
printf("%d\n", sizeof(struct s3));//24
在跨平台程序中可以使用 #pragma pack() 自定义对齐数,否则,不同平台下的默认对齐数不同,就会导致结构体内存布局不同,从而容易引入bug。
二、位段
位段与结构体的声明类似,但有两个不同:
- 位段的成员必须是 int 、 unsigned int 、signed int
- 位段的后面必须有一个冒号和一个数字,数字的单位为位。
- 位段不跨平台
struct A
{
int _a : 2;
int _b : 5;
int _c : 10;
int _d : 30;
};//8字节
三、枚举
将有可能出现的值一一列举
enum Day
{
Mon,
Tues,
Wes,
Thur,
Fri,
Sat,
Sun
};
这些有可能的值都是有值的,默认从0开始,一次递增1,也可以定义的时候赋值。其在内存中的存贮和int是一样的,只是为了可读性更强。
四、联合
联合是一种特殊的自定义类型,变量中也包含了一系列的成员,特点是这些成员公用一块空间。
- 会导致修改了一个成员就会影响到其他成员的内容。
- 如果某个内存空间可以安装多种方式来解释,就适合联合。
应用: IP地址“点分十进制”=>整数形式
判断当前计算机的大小端存储
union Un{
char a;
int b;
};
int main()
{
union Un u;
u.b = 0x1;
if (u.a == 0x01)
{
printf("小端");
}
else
{
printf("大端");
}
return 0;
}