结构体
结构体的声明
struct student
{
int age;//年龄
char name[20];//名字
char id[20];//学号
char sex[5];//性别
};
结构体变量的定义和初始化
struct student
{
int age;//年龄
char name[20];//名字
char id[20];//学号
char sex[5];//性别
}s1 = {10,"lisi","2000","nan"};
int main()
{
struct student s2 = {20,"wangwu","100","nan"};
}
在知道了结构体如何声明定义初始化之后,这里我将向大家介绍结构体中一个很有意思的知识点——内存对齐
结构体的内存对齐
struct S
{
char a;
int b;
char c;
};
int main()
{
struct S s;
printf("%d\n", sizeof(s));
return 0;
}
我们来看这个代码,你认为结构体s的大小是多少?是6个字节吗?
咦?明明只是放了两个字符变量和一个整形变量,为什么大小是12字节呢?
我们应该如何计算结构体的大小呢?
首先,我们要先掌握结构体内存对其的规则
1. 第一个成员在与结构体变量偏移量为0的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
VS中默认的值为8
3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
![](https://img-blog.csdnimg.cn/3617dec63296464ba2301d6e77b7f4b5.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAZGlsaTMy,size_20,color_FFFFFF,t_70,g_se,x_16)
可能这里就有同学觉得奇怪:为什么要有内存对齐这样的规则呢?
大部分的参考资料是这样解释的:
1.平台原因(移植问题)
struct S
{
char a;
char c;
int b;
};
int main()
{
struct S s;
printf("%d\n", sizeof(s));
return 0;
}
可以看到,只是交换了b和c的位置,该结构体的大小就从12字节将为8字节。
所以,当你在创建结构体时,可以把占用空间小的成员尽量集中到一起。
结构体传参
见识到了如何内存对齐之后,我们再来看结构体传参
请看如下代码
struct S {
int data[1000];
int num;
};
struct S s = { {1,2,3,4}, 1000 };
void print1(struct S s)
{
printf("%d\n", s.num);
}
void print2(struct S* ps)
{
printf("%d\n", ps->num);
}
int main()
{
print1(s);
print2(&s);
return 0;
}
你觉得print1和print2哪一个函数更好呢?
答案是print2
函数传参时,参数是会压栈的,会有时间和内存上的系统开销,如果传送一个结构题对象时,结构体过大,例如本段代码中有一个包含1000个整形的数组,参数压栈的系统开销较大,所以会导致性能下降。
位段
struct A {
int _a:2;
int _b:5;
int _c:10;
int _d:30;
};
![](https://img-blog.csdnimg.cn/1339d164ac5849e9a226920a8cf99356.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAZGlsaTMy,size_20,color_FFFFFF,t_70,g_se,x_16)
冒号后面跟着的数字代表了该成员占多少个比特位
位段的内存分配
与结构体相同,位段也有自己的内存分配规则
struct S {
char a : 3;
char b : 4;
char c : 5;
char d : 4;
};
int main()
{
struct S s = { 0 };
s.a = 10; s.b = 12; s.c = 3; s.d = 4;
return 0;
}
![](https://img-blog.csdnimg.cn/7a909f0f7f6f42998b4574a5ad7671ab.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAZGlsaTMy,size_20,color_FFFFFF,t_70,g_se,x_16)
![](https://img-blog.csdnimg.cn/fac1af321d8a44bbb53fd995235cbaa2.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAZGlsaTMy,size_20,color_FFFFFF,t_70,g_se,x_16)
位段的跨平台问题
2. 位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机
器会出问题。
3. 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
4. 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是
舍弃剩余的位还是利用,这是不确定的
枚举
枚举,顾名思义就是列举
把可能的值一一列举
例如我们生活中
一周的七天
人的性别
enum Day//星期
{
Mon,
Tues,
Wed,
Thur,
Fri,
Sat,
Sun
};
enum Sex//性别
{
MALE,
FEMALE,
SECRET
};
大括号内部的成员则叫枚举常量
这些常量都是有值的,默认从0开始,也可以给他赋值
enum Color//颜色
{
RED = 1,
GREEN = 2,
BLUE = 4
};
枚举的优点
可以发现,我们也能使用define来定义常量,为什么要使用枚举呢?
联合体(共用体)
联合体的定义
union Un
{
char c;
int i;
};
int main()
{
//联合变量的定义
union Un un;
//计算连个变量的大小
printf("%d\n", sizeof(un));
}
联合体的特点
联合至少得有能力保存最大的那个成员)。
union Un
{
int i;
char c;
};
int main()
{
union Un un;
// 下面输出的结果是一样的吗?
printf("%p\n", &(un.i));
printf("%p\n", &(un.c));
//下面输出的结果是什么?
un.i = 0x11223344;
un.c = 0x55;
printf("%x\n", un.i);
}
大概知道了联合体的概念后,我们用联合体求解如何判断大小端
union Un
{
int i;
char c;
};
int check()
{
union Un u;
u.i = 1;
return u.c;
}
int main()
{
int x = check();
if (x) printf("小端\n");
else printf("大端\n");
}
联合体的大小计算
union Un1
{
char c[5];
int i;
};
int main()
{
printf("%d\n", sizeof(union Un1));
return 0;
}
本篇完,感谢你的阅读!全文来自本人的一些拙见,希望能对正在学习结构体的同学起到一些帮助,若您在阅读过程中发现错误,劳请在评论区中指正,万分感谢!