一.🏠引言
在前面我们学了int , char , float等数据类型,这些属于内置数据类型,如果我们想一次性使用多个类型,比如我们生活中登记某个人的信息,一个数据类型是不够的,这时候就可以使用我们的自定义类型。
二.🏠结构体
😈 结构体的声明
😈 结构体变量的创建与初始化
1.结构体变量创建
结构体变量创建有两种方式:
struct S
{
int age;
char name[20];
char c1;
}s1;
//直接在声明结构体之后创建
int main()
{
struct S s2;
//在主函数内部创建
return 0;
}
2.结构体变量的初始化
结构体变量初始化分为按默认顺序初始化和自定义顺序初始化。对于自定义初始化,需要用.操作符加成员名来初始化。
struct S
{
int age;
char name[20];
char c1;
}s1 = {16,"lisi",'s'};
//直接在声明结构体之后初始化
int main()
{
struct S s2 = { 12,"zhangsan",'x' };//按默认顺序初始化
struct S s3 = { .name = "lisi",.age = 12,.c1 = 'y' };//不按默认顺序初始化
return 0;
}
😈 结构体的特殊声明
struct
{
int a;
char b;
float c;
}x;
struct
{
int a;
char b;
float c;
}a[20],*p;
此时让p=&x能正常运行吗?答案是不行的
由此我们得出
编译器会把上⾯的两个声明当成完全不同的两个类型,所以是⾮法的。
😈 结构体的自引用
有的同学可能想玩些骚操作在结构中包含⼀个类型为该结构本⾝的成员,是否可以呢?
struct Node
{
int data;
struct Node next;
};
分析:当我们用sizeof计算这个结构体大小时,他的大小是int+struct Node=int + int +struct Node...
就这样一直套娃导致大小无穷大,这显然是不行的。
正确自引用:
struct Node
{
int data;
struct Node* next;
};
为什么这样写呢?原因在于我们可以通过指针也就是地址来找到下一个节点,同时指针变量大小是确定的。
学会了自引用我们觉得struct Node 太长了是否能重定义一下?
typedef struct
{
int data;
Node* next;
}Node;
这种写法就是典型的先有蛋还是先有坤的问题。我们在重命名时之前就用了Node指针这肯定是不行的。正确写法如下:
typedef struct Node
{
int data;
struct Node* next;
}Node;
😈 结构体的内存对齐
struct S1
{
char c1;
int age;
char c2;
};
struct S2
{
char c1;
char c2;
int age;
};
int main()
{
printf("%zd\n", sizeof(struct S1));
printf("%zd\n", sizeof(struct S2));
return 0;
}
对于这两个有相同成员的结构体类型大小是否相等呢?这时我们需要结构体的内存对齐
结构体的对齐规则
struct S2
{
char c1; //1
char c2; //1
int age; //4
//成员最大对齐数为4
}s2;
struct S4
{
char c1; //1
struct S2 s2;//4
double d;//8
//24
};
同样画图直观感受下:
依照嵌套结构体对齐规则,该变量大小就是24
结构体内存对齐原因
由结构体内存对齐我们得到:要想结构体类型尽量小节省空间,我们可以把小变量放前面。
修改默认对齐数
#pragma pack(1)
struct S1
{
char c1;
int age;
char c2;
};
int main()
{
printf("%zd\n", sizeof(struct S1));//6
return 0;
}
此时结果就是6.
结构体传参
结构体传参有两种方式,一种是结构体传参一种是地址传参。
//结构体传参
void print1(struct S s)
{
printf("%d\n", s.num);
}
//结构体地址传参
void print2(struct S* ps)
{
printf("%d\n", ps->num);
}
😈结构体位段
我们学习了结构体内存对齐会浪费一定空间,那有什么办法可以减少一定的浪费呢?这时我们可以了解结构体位段。
结构体位段是基于结构体的(它也有一定的内存对齐)
1. 什么是位段
位段的声明和结构是类似的,有两个不同:
struct A
{
int _a:2;
int _b:5;
int _c:10;
int _d:30;
};
解释:a:2指给2存两个bit位 以此类推
那这个结构体位段的大小是多少呢?
2.结构体位段内存分配
//⼀个例⼦
struct S
{
char a:3;
char b:4;
char c:5;
char d:4;
};
struct S s = {0};
s.a = 10;
s.b = 12;
s.c = 3;
s.d = 4;
//空间是如何开辟的?
图形表示:
3.位段的跨平台
struct Test1
{
char a : 1;
int b : 4;
char c : 1;
};
struct Test2
{
char a : 1;
char c : 1;
int b : 4;
};
int main()
{
printf("%zd\n", sizeof(struct Test1));//12
printf("%zd", sizeof(struct Test2));//8
return 0;
}