各位帅哥靓女们,我是猪猪,这期给大家带来的是自定义类型:结构体,枚举,联合(一),也就是带带大家看看更多的关于自定义类型的内容,老规矩,如果猪猪有哪里说的不对的地方还请于评论区斧正,如果觉得猪猪讲的还可以的话,还请给猪猪一键三连,毕竟猪猪码字不易。
【一】结构体
1.什么是结构体?
我们c语言中有几个基础的类型,比如int,char,double,当你存储一个人年龄数据的时候可以去使用int类型,当你去存储别人的姓名的数据的时候你会去使用char[]类型,当你去储存一个人的升高的数据的时候你可以使用double的类型的数据,这都是可以单独的拿出来去记录去使用的,但是当你一个人想去记录一个人整体的信息的时候,也就是记录一个人的身高体重和年龄的时候你该如何去储存呢?这个时候就需要使用到集合讲几个小的元素统筹在一起变成一个大的元素,而大的元素其实就是结构体,小的元素就是基础数据类型。
2.结构体的声明
struct tag
{
member-list;
}variable-list;
struct tag是为新的数据类型,也就是结构体的名字,member—list是其内部的成员变量,variable-list是用这个新的数据类型创建的变量名。
例如在我们描述一个学生的时候,我们需要去记录他的名字,年龄,性别,学号。那么这个结构体的内部元素我们可以写为:
struct Stu{
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
};
3.匿名结构体
就是讲这个结构体不写出结构体标签,也就是这样:
struct
{
int a;
char b;
float c;
}x;
这个在结构体中是被允许的,但是只能使用一次,也就是一次性的,可以通过x调用内部的值,但是不能赋值或者被赋值给别人。
4.结构体自引用
有的人学了数据结构就知道,结构体可以是链表的节点,存储数据和指向下个存储位置的节点,但是有人想过没有,为啥节点里面存储的是结构体的指针类型而不是他自己本身?其实用我们自然人类的想法也是可以想明白的,如果允许自己镶嵌自己的话,那么就会产生无限套娃的情况,所以结构体内部是可以存储别的结构体类型而不能储存自身的结构体类型。所以就出现了指针的方式去指向下一个结构体的,从而实现链式访问。代码如下:
struct Node
{
int data;
struct Node* next;
};
5.结构体的定义和初始化问题
其实这个是非常简单的,看以下代码就可知:
struct Point
{
int x;
int y;
}p1; //声明类型的同时定义变量p1
struct Point p2; //定义结构体变量p2
//初始化:定义变量的同时赋初值。
struct Point p3 = {x, y};
struct Stu //类型声明
{
char name[15];//名字
int age; //年龄
};
struct Stu s = {"zhangsan", 20};//初始化
struct Node
{
int data;
struct Point p;
struct Node* next;
}n1 = {10, {4,5}, NULL}; //结构体嵌套初始化
struct Node n2 = {20, {5, 6}, NULL};//结构体嵌套初始化
6.结构体的内存对齐和结构体的大小
很多人一看?啥?结构体大小,这玩意大小不就是所以内部的元素的大小相加就可以得出的吗?孩子你还是太年轻了,来看一下代码:
struct S1
{
char c1;
int i;
char c2;
};
printf("%d\n", sizeof(struct S1));
struct S2
{
char c1;
char c2;
int i;
};
printf("%d\n", sizeof(struct S2));
你觉得这两个输出结果是一样的吗?答案是否定的,那么结构体的内存大小到底是咋算的呢?
看以下的运算规则:
1. 第一个成员在与结构体变量偏移量为0的地址处。 2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。 对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。 VS中默认的值为8 3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。 4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整 体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
我们能很容易算出第一个大小是12,第二个是8
为什么存在内存对其?
其实就是对于未对其的数据需要两次的内存访问,但是对于这个对其的数据仅仅需要一次的内存访问。
其实总的来说内存对齐就是一种拿空间换取时间的做法,那么设计结构体的时候,为了让结构体足够的小,尽量让占用空间小的成员集中在一起。
7.修改默认对其数,vs2019的默认对其数是8,但是却可以通过这个修改这个对其数字的值让其更加的紧凑。#pragma pack(4)//就是修改默认对其数为4。
tips:当你将这个默认的对其数为1时候,就实现了这个结构体的空间紧凑。
【二】位段
1.什么是位段?
位段和结构体的作用是类似的,只不过结构体的内部的组成元素是c语言的各种基础元素,而位段的成员时int,unsigned int 或signed int。位段的成员后面有一个冒号和一个数字。数字表示的是这个数据占用的比特位的个数。简单来说,位段时各种整数的集合,而且各个成员的占用的比特位是固定的,不变的。
2.位段的大小?
位段基本上都是按照一个整形也就是八个字节开辟的,然后这个按照所需的字节数进行排序,不够则开辟新的空间,并舍弃上一个字节多余的空间。
3.位段的跨平台性
1. int 位段被当成有符号数还是无符号数是不确定的。 2. 位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机 器会出问题。 3. 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。 4. 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是 舍弃剩余的位还是利用,这是不确定的。
tips:
总的来说,位段和结构体相比可以更好的达到目的,且使用的内存更小。
以上就是这期猪猪的全部内容了,觉得猪猪写的还不错的还请一键三连,毕竟猪猪码字不易,你们的攒和关注就是对猪猪的最好鼓励。