目录
结构体的特殊声明
结构体的自引用
结构体的特殊声明
在声明结构的时候,可以不完全的声明。
比如:
struct
{
int a;
char b;
float c;
}x;
以上结构在声明的时候省略掉了结构体标签(tag)。
那么会有什么影响呢?
int main()
{
struct x;
return 0;
}
由于摘掉了标签,我们再main函数内进行变量赋值的时候,无从下手也无法成功赋值,所以得到结论,这种摘取标签的声明方式,只能使用一次,而这一次也只能是在声明的时候进行创建变量使用。
也就是这种声明,是一次性的。
又比如:
struct
{
int a;
char b;
float c;
}x;
struct
{
int a;
char b;
float c;
}a[20], *p;
当不看标签 ,我们可以发现两个结构体的成员一样,所以当我们进行以下操作时,是否成立呢?
p = &x;
*p是一个结构体类型的指针变量,而x也是一个结构体类型的变量,且二者的结构体去除名字外,完全一样,那么我们是否可以将x的地址存放再p中呢?
答案是不允许的,因为编译器会把上⾯的两个声明当成完全不同的两个类型,所以是⾮法的。 匿名的结构体类型,如果没有对结构体类型重命名的话,基本上只能使⽤⼀次。
结构体的自引用
什么叫做结构体的自引用?
拿数据结构中的顺序表举例,自引用就是当你找到一个数字1的时候,你可以通过数字1顺藤摸瓜找到数字2,又可以从数字2顺藤摸瓜找到数字3,以此类推。
而结构体的自引用也是如此,不过其本身应该更类似与数据结构体中的链表。
通过1找到2,通过2找到3,通过3找到4,通过4找到5,这其中的每一个数字都是一个节点,这一个节点包含着前往下一个节点的线索,以此类推便可以顺藤摸瓜找到最后。
换到结构体身上便是一个结构体中包含着下一个结构体,且两个结构体是相同类型的,同名同标签(名 = 标签,不是变量名是结构体名)
那么就有了以下代码:
struct Node
{
int data;
struct Node next;
};
- 但,这个代码真的正确吗?
- 直接包含着下一个同类型同名的结构体,而这个被包含的结构体是否也包含着另一个同名的结构体 呢?
- 就像俄罗斯套娃一样,结构体1内包含结构体2,结构体2包含结构体3,结构体3包含结构体4,等等。
- 若这样,我们就不知道最外面那个结构体的大小是多少。
- 所以,以上代码是错误的,这种无限套娃使得我们不知道最外面的结构体大小究竟是多少个字节。
而因此我们又通过了数据结构的链表特点诞生了以下代码:
struct Node
{
int data;
struct Node* next;
};
根据链表的特点,我们将节点分为两个部分,一个部分存放的结构体本身的数据,另一个部分存放了下一个同类型同名的结构体的地址,这样便很好的解决了问题。
而同时,也会产生一种奇怪的写法:
typedef struct
{
int data;
Node* next;
}Node;
使用typedef对一个结构体进行重命名,将这个特殊声明的结构体重新命名为了Node,但是这个结构体内部也有一个叫Node的成员,这就产生了歧义。
类似先有鸡还是先有蛋的问题出现了。
但这种问题再编译器内部是不行的。
所以正确的写法是:定义结构体不要使⽤匿名结构体了
typedef struct Node
{
int data;
struct Node* next;
}Node;
完善这个特殊声明,加上名字(标签),而后直接进行重命名为结构体的名字(标签)使用。