📋 前言
🌈hello! 各位宝子们大家好啊,结构体的基本使用和常见错误在上一篇详细讲解过了,不知道大家都学会了没有。
⛳️今天给大家来个硬菜,教点高级点的结构体结构,给我们的数据结构开个好头!废话不多说直接进入正题
📚本期文章收录在《C语言进阶篇》,大家有兴趣可以看看呐!
⛺️ 欢迎铁汁们 ✔️ 点赞 👍 收藏 ⭐留言 📝!
1 结构体的声明
1.1 结构的基础知识
这个部分博主在前一篇博客已经详细讲解过了,一俩句话也解释不清楚,结构体这方面基础不是很好的铁铁们可以去阅读一下这篇文章哦!万字详解包看包会!
🔥 注:上一篇结构体万字解析的链接《结构体的基础讲解》
1.2 结构的声明
1.2.1 . 匿名结构体类型声明
在声明结构的时候,也可以不完全的声明。面的两个结构在声明的时候省略掉了结构体标签(tag),看下有什么后果。
- 而这就叫匿名结构体类型
📚 代码演示:
//匿名结构体类型 struct { int a; char b; float c; }x; struct { int a; char b; float c; }a[20], * p;q
1.2.2 匿名结构体类型的的缺陷
那么匿名结构体有什么缺陷呢?其实有俩个缺陷匿名结构体第一没有 标签名,连名字都没有所以只能在创建结构体时定义。
- 只能在创建结构体时定义结构体变量
- 相同类型的结构体,我们编译器认为是不一样的
假如我们有俩个相同类型的 匿名结构体
,一个用来创建。一个创建 匿名结构体指针
用来存放相同类型的结构体变量地址!
📚 代码演示:
//匿名结构体类型 struct { int a; char b; float c; }x; struct { int a; char b; float c; }* p; int main() { p = &x; return 0; }
📑 代码结果:
这里我们就可以看出虽然都是相同类型的匿名结构体,但是在编译期间我们的编译器认为他们俩类型是不一样的。
- 相同类型的
匿名
结构体指针,接收不了相同类型匿名结构体的地址
总结:
- 匿名结构体只能在创建是定义
- 相同类型的匿名结构体,编译器会这两个声明当成完全不同的两个类型。
- 所以匿名结构体只适合,那种只用一次的结构体上用法很少。
2. 结构的自引用
那么结构体如果想包含一个该结构本身的成员是否可以呢?答案是可以的,这种用法我们在数据结构这门课 链表时会经常使用!
- 那么我们看下面这段代码,自引用结构体是否可以这样定义呢?
📚 代码演示:
//代码1 struct Node { int data; struct Node next; }; //可行否?
如果可以,那 sizeof(struct Node)是多少?诶这里我们就会发现我们根本计算不了这个结构体的大小是多少!
- 这里就和套娃一样,
int data
我们知道是四个字节- 而
struct Node
里面又包含了struct Node
这个根本就算不了嘛!逻辑上就错误了!
2.1 结构体自引用的作用
在我们数据结构体中有一个叫做链表的数据结构,这里就不给大家详细解释了,只给大家见见猪跑!免得搞混了。链表是我们数据结构中用来指向相同类型的元素但是在不同空间里的连续存储方式。
- 使他们向像一个链子一样可以相互链接访问
大家看着张图是不是就明白很多呢? 我们想在节点一找到相同类型的下一个节点:
- 诶!那这样我们只需要把相同类型节点的地址存放到上一个节点处是不是就可以了?
- 而不是去存放下一个节点的内容。那么我们就定义一个结构体
- 他的成员一个负责存放数组,一个负责存放下一个地点的地址
📚 代码演示:
//代码2 struct Node { int data; struct Node* next; };
这样我们就可以访问一块不连续空间但是,是相同类型的结构体变量了。也可以对比数组
- 数组是一块连续的空间里存放相同类型的数据
- 链表是一块不连续的空间里存放不相同类型的数据
- 而这就是结构体自引用的妙用了
2.2 结构体自引用的注意事项
但是在使用的时候,有些人会犯这样的错误一定要注意。
- 我们知道结构体可以重命名而很多人就会把重名的结构体当成结构体成员。
- 但这是非常错误的
//代码3 typedef struct { int data; Node* next; }Node; //这样写代码,可行否?
📑 代码结果:
这时在编译期间就会发生错误,我们typedef 重定义还没生效呢!你就开始使用重定义之后的类型名了。
✅ 原因:
结构体重定义在结构体结束时最后一行才生效,但是我们在重定义生效之前就想使用这肯定回发生错误呢!
- 正确的做法是在结构体里面我们还是使用未重命名之前的标签名。
//解决方案: typedef struct Node { int data;//数据域 struct Node* next;//指针域 }Node;