一.结构体
结构是一些值的集合,称为他的成员,值的类型可以不同(相当于内部成员类型不同的数组)。
1.结构体的声明:
struct tag { //tag为结构体名字
member-list ; // 成员必须在声明时一一列举;(包括类型与名字)
} variable-list ;// 创建具体变量
例1:
这个声明创建了一个x[20]结构体数组,y结构体指针。但没有为结构体命名,所以在创建相同结构体类型变量必须重新声明。
struct {
int a;
char b;
float c;
}x[20], *y;
例2:
这个声明没有创建变量,但命名了结构体,所以可在创建变量时直接用struct+结构体名字(stu)+变量名;。
struct stu{
int a;
char b;
float c;
};
struct stu x;// 定义了一个x结构体变量
例3:
运用typedef创建新类型。与例2区别在于创建变量时直接用结构体名字(stu)+变量名;。
typedef struct {
int a;
char b;
float c;
}stu;
stu x;// 定义了一个x结构体变量
2.结构体访问
struct {
int a;
char b;
float c;
}x[20], *y;
A.直接访问: 通过**点操作符(.)**访问,左边为结构变量名,右边为访问成员名。
x[5].a;
B.间接访问:通过结构体指针进行访问。(->),左边为指针名,右边为访问成员名。
y->a;
3.结构的自引用: 必须使用指针进行自引用;
struct stu {
int a;
char b;
struct stu *str;
}y;
4.结构的初始化
struct stu {
int a;
char b;
int a[2];
}y={2,'a',{1,3}};
或者
typedef struct{
int a;
char b;
int c[2];
}stu;
stu y = { 2,'a',{1,3} };
5.结构体传参:(使用地址传参)
节省栈上空间!
6.内存对齐(超级重要)
对齐规则:
- 第一个成员的首地址为0
- 每个成员的首地址是自身大小的整数倍
补充:其实需要自身大小与系统默认对齐数进行比较取最小值。但vs中最小对齐数为8,大于等于最大的数据类型,可以忽略。 - 以整个结构体中(包括子结构体)最大长度的类型为标准进行对齐【整体对齐】
例
struct stu {
char a;
double b;
char c;
int d[2];
int * e;
char f;
}y;
printf("%d\n", sizeof(y));
printf("%p\n", &y.a);
printf("%p\n", &y.b);
printf("%p\n", &y.c);
printf("%p\n", &y.d);
printf("%p\n", &y.e);
printf("%p\n", &y.f);
分析:
- 第一个成员地址从0开始,为char型,所以占一个字节,此时下个空地址为1;
- 第二个成员为double型,占8个字节,不可以从1开始,所以内存对齐到8。此时下个空地址为16;
- 第三个成员为char型,占一个字节,可以从地址16开始,不需要内存对齐,此时下个空地址为17;
- 第四个成员为int型数组,占4*2个字节,不可以从17开始,需内存对齐到20,,此时下个空地址为28;
- 第五个成员为指针,占4个字节,可以从28开始,不需要内存对齐,此时下个空地址为32;
- 第六个成员为char型,可以从32开始,不需要内存对齐,此时下个空地址为33;
- 整个结构体此时占33个字节,最大对齐数为8,需内存对齐至40;
二.位段(节约资源,但不可跨平台)
位段声明与结构体类似,不同点在于:
1.位段成员必须为int,signed int或者unsigned int,char;
2.位段成员名后必须跟** : 加一个数字 **
例:
struct A
{
int _a : 2;
int _b : 5;
int _c : 10;
int _d : 30;
};
struct B
{
char _a : 2;
char _b : 5;
char _c : 2;
char _d : 3;
};
struct C
{
int _a : 30;
int _b : 30;
int _c : 10;
int _d : 30;
};
printf("%d\n", sizeof(struct A));//8
printf("%d\n", sizeof(struct B));//2
printf("%d\n", sizeof(struct C));//16
地址分析图如下:
1.
3.
缺陷(不可跨平台):
- int位段被当成有符号还是无符号不确定的。
- 位段中最大位数的数目不能确定。(16位机器最大16,32位机器最大32,写成27在16位机器会出现问题。)
- 位段的成员在内存中内存分配从左向右还是从右向左尚未定义。
- 当一个结构体包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余时,是舍弃还是利用的,这也是不确定的。