结构体的创建和初始化:
常见定义方法:
1.其中A是结构体名称,a1,a2为结构体中的属性,as2是结构体对象名。
struct A
{
int a1;
char a2;
}as2;
2.此处为匿名结构体,结构体无名称,b1,b2为结构体中的属性,B是结构体对象名。
struct
{
int b1;
char b2;
}B;
3.使用typedef定义的结构体,结构体名称为C, c1,c2为结构体中的属性,没定义结构体对象。
typedef struct C
{
float c1;
int c2;
};
结构体的初始化:
对应上述结构体定义序号:
1.结构体对象可以在main()函数内部创建也可以在外部创建,二者的区别就是作用域不同
如下代码中:as1只能在当前的大括号中使用,而as2的作用域是整个函数。可以理解为:
as1类似局部变量,as2类似全局变量。
#include<stdio.h>
struct A
{
int a1;
char a2;
}as2;
int main()
{
{
struct A as1 = {10,'a'};
}
as2.a1;
//as1.a1; -- err
return 0;
}
2.由于该结构体为匿名结构体并且已经有对象,可以直接定义,按照属性顺序赋值即可。
#include<stdio.h>
struct
{
int b1;
char b2;
}B;
int main()
{
B = { 20,'b' };
return 0;
}
3.和情况一相同。
#include<stdio.h>
typedef struct C
{
float c1;
int c2;
};
int main()
{
struct C c = { 'c',1.2 };
return 0;
}
结构体传参
法一:按照结构体成员直接传参(不推荐),如下面代码中的print1,传入a,直接采用struct A a接收
相当于直接传值达到传参的目的。
法二:按照结构体成员指针传参(推荐),如下面代码中的print2,传入b的地址,采用struct B *b接收
相当于直接传地址达到传参的目的。较于上一方法,传值调用较为节省内存,且传参速度更快。为了让成员b的内容不变,可以在Struct B *b 前加 const修饰.
#include<stdio.h>
struct A
{
int x;
char y;
};
struct B
{
int x;
char y;
};
void print1(struct A a)
{
printf("%d %c\n", a.x, a.y);
}
void print2(const struct B *b)
{
printf("%d %c\n", b->x, b->y);
}
int main()
{
struct A a = { 10,'a' };
struct B b = { 20,'b' };
print1(a);
print2(&b);
return 0;
}
结构体内存空间分配(内存对齐):
结构体的所占空间大小遵循对齐数规则:
结构体对齐规则:
//1.结构体的第一个成员对齐和结构体变量起始位置偏移量为0的地址处
//2.其他成员变量要对其到某个数字(对齐数)的整数的地址处,开始存放
// 对齐数 = 编译器默认对齐数(Vs中为8) 和 成员变量类型大小的 较小值
//3.结构体总大小为最大对齐数(成员属性之间)的整数倍
此处用例题来探讨内存对齐~!
例1:求结构体s1所占空间的大小
#include<stdio.h>
struct S1
{
char c1;
char c2;
int a;
};
int main()
{
struct S1 s1 = { 'a','b',100 };
printf("%zd\n", sizeof(s1));
return 0;
}
首先确定 系统默认对齐数 大小为 8,
c1对齐数(对应类型所占字节大小)为1, c2对齐数为1, a对齐数为4
1.根据第一条规则,结构体的第一个成员对齐和结构体变量起始位置偏移量为0的地址处,
c1所占大小为1个字节,地址0刚好可以存放,如图:
2.规则二:其他成员变量要对其到某个数字(对齐数)的整数的地址处,开始存放
已知c2的对齐数为1,c1后地址为1的整数倍的是地址1,故c2存放在地址1处
c2所占大小为1个字节,地址1刚好可以存放
3.规则二:其他成员变量要对其到某个数字(对齐数)的整数的地址处,开始存放
已知a的对齐数为4,c2后地址为4的整数倍的是地址4,故a存放在地址4处,
地址2、3浪费, a所占大小为4个字节在地址4向后存储4个字节直到地址7,如图:
4.从地址0-7共占8个字节,规则三:结构体总大小为最大对齐数(成员属性之间)的整数倍
//成员属性有c1,c2,a其中最大对齐数为a:4,而所算的的8个字节是4的倍数
故该结构体的大小为 8个字节。
例2:求结构体s2所占空间的大小
#include<stdio.h>
struct S2
{
char c1;
int a;
char c2;
};
int main()
{
struct S2 s2 = { 'a',100,'b' };
printf("%zd\n", sizeof(s2));
return 0;
}
首先确定 系统默认对齐数 大小为 8,
c1对齐数(对应类型所占字节大小)为1, a对齐数为4, c2对齐数为1
1.根据第一条规则,结构体的第一个成员对齐和结构体变量起始位置偏移量为0的地址处,
c1所占大小为1个字节,地址0刚好可以存放,如图:
2.规则二:其他成员变量要对其到某个数字(对齐数)的整数的地址处,开始存放
已知a的对齐数为4,c1后地址为4的整数倍的是地址4,故a存放在地址4处,
地址1、2、3浪费, a所占大小为4个字节在地址4向后存储4个字节直到地址7,如图:
3.已知c2的对齐数为1,a后地址为1的整数倍的是地址8,故c2存放在地址8处
c2所占大小为1个字节,地址8刚好可以存放,如图:
4.从地址0-8共占9个字节,规则三:结构体总大小为最大对齐数(成员属性之间)的整数倍
//成员属性有c1,c2,a其中最大对齐数为a:4,而所算的的9个字节不是是4的倍数!!!
注意:当不满足规则三时,要在内存中申请空间,使结构体大小为最大对齐数的整数倍,而距离地 址9最近,且满足最大对齐数的整数倍的地址是 地址12
故空间地址9、10、11、12被浪费,结构体所占内存大小为 12
//结构体的大小判断就靠这三条规则,希望同学们能够熟练应用,共勉!!!
//是不是忘了什么,你懂的!!!!!