从浅入深掌握结构体1(C语言)

前言
结构体作为自定义类型的一大组成部分,自然十分的重要,在该篇博客中,我们将从浅入深的带大家了解结构体。如果对C语言学习感兴趣额小伙伴千万不要忘记关注博主哦~,那么话不多说我们进入正题吧

文章目录

  • 1,结构体的介绍
  • 2,结构体变量的创建和初始化
  • 3,结构体的内存对齐
  • 4,尾声

1,结构体的介绍

结构体是存储不同类型的集合,这句话怎么讲?假如我们要描述一个学生的名字,年龄,成绩。
首先名字应该是一个字符串,年龄应该是一个整形,而成绩应该是一个浮点数。我们想存储这个学生的信息不能够用某一种单独的类型储存,这时就应该使用我们的结构体。在结构体中我们可以定义各种类型。

2,结构体变量的创建和初始化

结构体变量的创建与使用
我将采用代码的方式进行讲解。
就拿刚才学生的信息来创建一个结构体,示例如下。

#include
struct student
{
	char name[20];//成员名这三个都是成员
	int age;
	float score;
};
int main()
{
	struct student stu1 = { "zhangsan",18,114.514 };//创建结构体变量stu1,struct student为类型名,其中储存了张三的名字年龄和成绩。//我们会发现输入数据是按照定义结构体成员的顺序输入的。
//那么我们能不能不按顺序输入呢?当然可以请看下面这种方法。
	struct student stu2 = { .age = 18,.score = 114.514,.name = "lisi" };//这样也可以吧数据储存到相应的位置。
	//打印出来stu1和stu2中的数据
		printf("%s %d %f\n%s %d %f", stu1.name,stu1.age,stu1.score, stu2.name, stu2.age, stu2.score);//在结构体变量后加.再加所需要的成员名即可找到相应的数据
	return 0;
}



在这里插入图片描述

结构体指针的创建与使用
请看如下代码。

#include
struct student
{
	char name[20];
	int age;
	float score;
};
int main()
{
	struct student stu1 = { "zhangsan",18,114.514 };
	struct student* s1 = &stu1;//结构体指针自然是用来储存结构体的地址的
	//那么我们怎么样通过指针取出所需要的数据呢?
	printf("%s %d %f\n%s %d %f", (*s1).name, (*s1).age, (*s1).score, s1->name, s1->age, s1->score);
	//显然是还有两种方法的一种是对结构体指针解引用找到其所指向的结构体,另一种则是同一个箭头->直接指向结构体中的成员,后者比较方便且可读性高
	return 0;
}

在这里插入图片描述

这样我们就了解了结构体变量和结构体指针的使用了。

3,结构体的内存对齐

首先我们先看下面这段代码会输出什么?

#include
struct s1
{
	char a;
	char b;
	int c;
};
struct s2
{
	char a;
	int c;
	char b;
};
int main()
{
	struct s1 w1;
	struct s2 w2;
	printf("%zd %zd", sizeof(w1), sizeof(w2));
	return 0;
}

s1和s2看上去貌似没有什么差别,都是又两个字符数据和一个整形数据组成的,所以结构体的大小应该是6个字节,那让我们来看看结果。
在这里插入图片描述
我们发现结果并不是6个字节而且两个还都不一样,这是因为结构体存在内存对齐。

规则:
每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。程序员可以通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。在vs编译器上默认对其系数为8.
1、数据成员对齐规则:结构体(struct)的数据成员,第一个数据成员放在offset(偏移量)为0的地方,以后每个数据成员的对齐按照对齐系数指定的数值和这个数据成员自身长度中,比较小的那个来进行。比如现在的偏移量时18,而要分配的数据类型占4个字节,比8(vs默认对齐数)小
那么这次对其数应该为4,我们分配给这个数据类型的内存的起点必须是4的倍数,18显然不是4的倍数,那么我们就要往后找空出19,来到20,20是4的倍数,所以这个数据类型分配的空间是20-24这段空间。
从浅入深掌握结构体1(C语言)_第1张图片

2、结构的整体对齐规则:在数据成员完成各自对齐之后,结构本身也要进行对齐,对齐将按照对其系数指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。比如现在分配好成员的内存空间后此时的偏移量为18,而最大数据成员为4个字节,比8小,那么4就会作为整体的对齐数,也就是说内存的结尾必须是4的倍数,18显然不是4的倍数,那么我们就会往后找,找到20为止,20个字节就是该结构体所被分配的空间(即大小),

那么回到这道题,根据这些知识让我们来看看为什么会输出8和12.
首先s1中我们分配空间的顺序是先给a再给b再给c。如图所示。
从浅入深掌握结构体1(C语言)_第2张图片
首先先分配a,a是一个char类型所以只占一个字节,这个值比默认对齐数小,所以1为这次的对其系数。可以直接放,接着分配b,大小又是1,又可以直接放,再接着是c,占4个字节,所以这次的对齐数是4,而此时的偏移量为2,不是4的倍数,所以我们要空出两格来到偏移量为4的地方来填c,填完之后整体的偏移量为8,此时的整体对其数为4,8是4的倍数。所以s1被分配了8个字节大小的空间。
那么我们再来看s2。
从浅入深掌握结构体1(C语言)_第3张图片
首先分给a一个字节,接着轮到c,c的大小是4,比8小所以此时4为对齐数,而此时的偏移量为1显然那不是4的倍数,所以后移到4,然后分配给c4个字节的空间,分配完之后的偏移量为8,然后开始给b分配,b的大小为1,此时对齐数为1,可以直接给b分配,分配完之后此时的偏移量为9,开始整体对其,abc中大小最大的为c,4个字节,比8小所以4是此时的整体对齐数,9显然不是4的倍数,所以我们要把偏移量往后移,移动到12停止,然后12就是s2所分配的内存大小。

对齐原因
1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2、性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
总体来说: 结构体的内存对⻬是拿空间来换取时间的做法 。

4,尾声

剩余的结构体知识我们将留到下一篇博客,一定要记得学习哦~
如果觉得博主讲的不错的话请给博主一个免费的关注,点赞,收藏吧!我们下期再见。

你可能感兴趣的:(c语言学习,c语言,服务器,开发语言)