结构体 详解

目录

一.基础详解

二.结构体变量初始化(一共5种)

三.   typedef 类型重命名

四.嵌套

五.匿名结构体

六.结构体作为函数参数

七.使用结构体指针

八.结构体内存计算

九.结构体自引用

十.结构体实现位段


一.基础详解

定义:它是不同数据类型的集合

1d148f9dc01d41338bf141d9920c7e8b.png

  • 结构体关键字是struct
  • Student是自定义的结构体名/结构体标签名/结构体名称(首字母最好大写,可以与变量区分)
  • {}里面放的是成员列表,或者叫结构体成员,结构体成员不能初始化,其中的id,age,name叫成员名
  • struct+结构体名=数据类型/结构类型/结构体类型, 这个数据类型也就和int,double等那些数据类型是一样的
  • 大括号内是成员列表,这个成员列表里面不仅可以有基本成员列表,还可以有复合数据类型,甚至还可以有结构体
     

二.结构体变量初始化(一共5种)

1.   默认顺序初始化

9c9bd31d72de4f7c9c2f74dd614c99f7.png

2.   自定义初始化顺序

abf42355df0b476fa0e32c04952da721.png

3.   定义时直接赋值

b8f2a51f218e49d1857e2899570241ad.png

4.   

aa67d334a97b483ca454ffdaad3e1170.png

5.   结构体数组初始化

db56944953184ebbba32577bba25d834.png

三.   typedef 类型重命名

其中type是类型,def是定义

重命名的优点:  减少麻烦,更加方便,简单

eg.

第1种写法:

cbc4f25ab7cb4422b8e612a569ad31b0.png

第2种写法:

d4c5e7ac5a8c4e64b6f6c59efd1cb239.png

四.嵌套

eg.在学生结构体里面去嵌套一个生日结构体

9f2cf38331274fda8755df4e392a6401.png

651baa7ee4b5438a9d38ebb8911d2504.png

五.匿名结构体

优点:嵌套在结构体中的结构体为匿名结构时,可以直接访问其成员

一般来说,结构体中的局部变量都是通过结构体名称来命名,这样会更加方便

但若是匿名结构体呢?

dad49421ac814669a42b521d447d51a4.png

e437eb11ea38497eb79f1928391c8069.png

d3b88f7c6d714f269d8527535f76e39c.png

在这个例子中,我们定义了一个匿名结构体变量 `employee`,它包含三个成员:`id`、`name` 和 `salary`。
我们没有为这个结构体指定一个类型名称,因此它不能被用来定义其他同类型的变量。

六.结构体作为函数参数

#include<stdio.h>
typedef struct Birthday
{
	int year;
	int month;
	int day;
}Birthday;


typedef struct Student
{
	int id;
	char name[10];
	int age;
	float score;

	Birthday birthday;

}Student;


int main()
{
	
	Student stu1 = { .id = 1001,.name = "xiaohong",.age = 28,.score = 99.0,
		.birthday = {.year = 2005,.month = 3,.day = 12} };
	Student stu2 = { .id = 1002,.name = "xiaoming",.age = 23,.score = 87.6,
		.birthday = {.year = 2006,.month = 7,.day = 23} };


	printf("%d\n%s\n%d\n%.2f\n%d\n%d\n%d\n", stu1.id, stu1.name, stu1.age,stu1.score,
		 stu1.birthday.year, stu1.birthday.month, stu1.birthday.day);
	printf("%d\n%s\n%d\n%.2f\n%d\n%d\n%d\n", stu2.id, stu2.name, stu2.age, stu2.score,
		stu2.birthday.year, stu2.birthday.month, stu2.birthday.day);
//像上面这样写2个printf打印虽然没有错,但是不规范,所以,就得通过让结构体作为函数参数
 //这个方法(具体参照下面的代码和这个代码的区别)

     return 0;
}

 更规范的写法:

#include<stdio.h>
typedef struct Birthday
{
	int year;
	int month;
	int day;
}Birthday;


typedef struct Student
{
	int id;
	char name[10];
	int age;
	float score;

	Birthday birthday;

}Student;

void printStudentinfo(Student stu)
{
	printf("%d\n%s\n%d\n%.2f\n%d\n%d\n%d\n", stu.id, stu.name, stu.age, stu.score,
		stu.birthday.year, stu.birthday.month, stu.birthday.day);

}


int main()
{

	Student stu1 = { .id = 1001,.name = "xiaohong",.age = 28,.score = 99.0,
		.birthday = {.year = 2005,.month = 3,.day = 12} };

	Student stu2 = { .id = 1002,.name = "xiaoming",.age = 23,.score = 87.6,
		.birthday = {.year = 2006,.month = 7,.day = 23} };


	printStudentinfo(stu1);
	printStudentinfo(stu2);
 
 
 return 0;
}

七.使用结构体指针

  • 像上面的printStudentinfo这种是值传递,它需要拷贝一份然后值传递,然后才能打印,这样的话,电脑的任务比较繁重,运行速率也会降低
  • 所以用指针,只用传递主函数里面stu1和stu2的地址,而不是拷贝,这样会加快代码的效率
#include<stdio.h>
typedef struct Birthday
{
	int year;
	int month;
	int day;
}Birthday;


typedef struct Student
{
	int id;
	char name[10];
	int age;
	float score;

	Birthday birthday;

}Student;

void printStudentinfo(Student *pStu)
{
	printf("%d\n%s\n%d\n%.2f\n%d\n%d\n%d\n", pStu->id, pStu->name, pStu->age, pStu->score,
		pStu->birthday.year, pStu->birthday.month, pStu->birthday.day);
//注意这里的year,month,day的这种嵌套,你就不用用->,用之前的.就行
}


int main()
{

	Student stu1 = { .id = 1001,.name = "xiaohong",.age = 28,.score = 99.0,
		.birthday = {.year = 2005,.month = 3,.day = 12} };

	Student stu2 = { .id = 1002,.name = "xiaoming",.age = 23,.score = 87.6,
		.birthday = {.year = 2006,.month = 7,.day = 23} };


	Student* pStu = &stu1;//即pStu这个指针指向stu1,即stu1的地址赋值给了pStu
	

	printStudentinfo(pStu);

	pStu = &stu2;//这一行因为pStu之前已经指向过了stu1,并且已经完成了打印,所以这一行就重新让它指向stu2
	printStudentinfo(pStu);
 
 
 return 0;
}

八.结构体内存计算

结构体内存计算用内存对齐

  • 对齐数是类型的大小
  • VS当中的默认对齐数是8
  • 对齐数和默认对齐数比较取较小值,这个较小值便在偏移量中找位置占据就行哪个位置?找这个较小值整数倍的位置占据,值是多少,偏移量即是多少
  • 当对齐数和默认对齐数比较之后得出的结果再放在一起比较,其中最大的,就是最大对齐数
  • 最后找出最大对齐数,也是在其整数倍处开始占据
  • 那什么时候会产生最大成员数,就是当是数组的时候,比如char c[5],对齐数是1,VS默认对齐数是8,而最大成员数是5
  • 当最大成员数不是最大对齐数的整数倍时,则要对齐到最大对齐数的整数倍

举例说明:

例1:

117e109dd47d421d88479246f760abb3.png

解析:

首先是char c1;   因为char的大小是1,VS默认对齐数是8,1和8作比较,选最小数为1

其次是int i;    是4和8作比较,选4,偏移量中选4的倍数处占据

最后是char c2;   是1和8作比较,选1,偏移量中选1的倍数处占据

最后选出最大对齐数是4(就是通过上面的1,4,1中选),再在偏移量中选4的倍数处占据

偏移量表格:

0char c1
1
2
3
4int i
5int i
6int i
7int i
8char c2
9
10
11
12最大对齐数是4
13

所以最终结果是12

例2:

54c5ced162bd41eb8de4f8792ae4a989.png

解析:

0d
1d
2d
3d
4d
5d
6d
7d
8c
9
10
11
12i
13i
14i
15i
16最大对齐数是8
17
18

例3:

嵌套结构体如何算?

05f3d3eb6bf84a18bac47b7171489fd6.png

解析:

如果是嵌套结构体,那就对齐到自己成员里最大对齐数的整数倍处就好

S3的结构体里最大对齐数是8,所以对齐到8的倍数处,占16个位置

S4里最大对齐数是16,因为是(1,16,8比较)

0char c1
1
2
3
4
5
6
7
8struct S3 s
9struct S3 s
10struct S3 s
11struct S3 s
12struct S3 s
13struct S3 s
14struct S3 s
15struct S3 s
16struct S3 s
17struct S3 s
18struct S3 s
19struct S3 s
20struct S3 s
21struct S3 s
22struct S3 s
23struct S3 s
24d
25d
26d
27d
28d
29d
30d
31d
32最大对齐数16
33

所以答案是32

九.结构体自引用

dd91d9c39a4949889df7815e89ebf37a.png

十.结构体实现位段

81b916a59b524500825663acd0f3ac16.png

写作不易,若有疑问,请各位大佬指教~感谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

麦麦在写代码

谢谢好大爹们请我喝奶茶啊啊啊啊

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值