我们在coding的时候,经常会定义各种各样的变量,如 int a,double b,long c等等,但是现实中仅仅靠这样的变量类型是不足够的,例如,我们需要描述一个人,他需要有性别,年龄,姓名等各种各样的属性,那问题来了,我们如何去定义这样的变量呢,这样的一个人的变量又属于什么类型呢?这时候就需要用到结构体了
结构体
结构体的声明
//声明一个学生类型
struct Stu
{
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
};//分号不能丢
结构体的定义
struct Stu
{
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
}student;//声明一个学生类型后直接进行定义
//也可以声明之后再进行定义
struct Stu student;
结构体的初始化
struct Stu
{
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
}student;
student.name = "zhangsan";
student.age = 20;
student.sex = "man";
student.id = "123456";
结构体的内存对齐
刚才定义的结构体如果我们计算它所占的字节,那么应该怎么计算呢?
struct Stu
{
char name;
int age;
char sex;
char id;
}student;
printf("%d ", sizeof(struct Stu));
//输出其实并不是我们想的几种变量字节数简单相加,而是需要字节对齐。
例如上面的例子,我们这样计算
char //1 + 3
int //4
char //1
char //1 + 2
前面的数为当前变量类型所占字节数,后面加的数是为了进行字节对齐所补的。
那么,我们要怎样进行字节对齐呢。
那些公式一样的概念就不再描述了,相信大家可以很容易在网上找到。我们直接来点技巧,可以快速算出来的那种。
1.先把每个类型所占字节写出来
2.题目如果给定了对齐数,就找出题目给定的对齐数和当前每个类型的对齐数中的较小值,作为判读补几个字节的对齐数。
3.从上到下看,当前的数字是否为下面一个数字的整数倍,若不是,则补为整数倍
4.判断下一个数时,将上面的数以及它们的对齐数相加,看是否为下一个数的整数倍,若不是,在当前数字上补齐。
5.最后一个数补几个字节,将所有之前的字节数相加,看是否为对齐数的整数倍,若不是,则补齐。
位段
位段和结构体非常相似,只是位段在成员变量后面加冒号和数字,但是成员变量只能是int/unsigned int/char类型
//在结构体成员后面加:和数字后就成了位段
//32位系统下
//一个char占一字节,32个bit位
//一个int占四字节,32*4个bit位
struct Stu
{
int name : 3;//name占一个int(32位系统下一个char占一字节,32个bit位)中的3个bit位
int age : 1;//占上一个int中的1个bit位
int sex : 3;//占上一个int中的3个bit位
int id : 6;//占上一个int中的6个bit位,如果占满了bit位,那么就要重新开辟一个int字节
};
//与结构体不同的是,冒号后的数字是代表着当前成员变量所占的位数(不是字节数),这样做的好处是节省空间。而对于计算位段的字节数来说,若当前位段的位数放不下时,会重新开辟相应的变量空间。
枚举
枚举中的变量默认从0开始,一次递增1,在定义的时候也可以赋初值,初值后的值也是依次递增。
enum Day//星期
{
Mon,
Tues,
Wed,
Thur,
Fri,
Sat,
Sun
};
联合体
联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小,当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。
union Un1
{
char c[5];
int i;
};
union Un2
{
short c[7];
int i;
};
sizeof(Un1); //8
sizeof(Un2);//16