声明结构体内部的结构体时指向结构体的指针

3

我有一个关于结构定义和指针的问题。

在链表节点结构的定义中,我们按照以下方式定义结构:

typedef struct node
{
    int data;
    struct node *next;
}Node;

为什么我们要使用这种声明方式而不是:

typedef struct node
{
    int data;
    struct node next; //changed this line
}Node;

提前感谢!


1
这个回答解决了您的疑问吗?为什么要使用指针? - John3136
1
因为在创建该类型的变量之前,您需要先完全定义它,但是您可以拥有一个指针,因为编译器已经知道在到达第4行时存在一个“struct node”(其定义不完整)。不完整数据类型的大小对编译器来说是未知的,但给定架构的指针大小始终相同。 - babon
1
即使允许在结构体内部声明结构体,但结构体的大小是不确定的,因为它取决于嵌套了多少级结构体。 - phuclv
1
你可以拥有一个指向不完整类型的指针,但你不能拥有一个不完整类型的实例。 - machine_1
1
如果这是可能的声明,那么结果的结构将会无限递归。一个节点包含一个节点,该节点又包含一个节点,以此类推,这将会无限循环,并且结构体大小将会无限大。 - TrentP
请注意第二段代码示例中含有无限递归的可能。 - machine_1
3个回答

1

在它的闭合大括号之后,结构体被定义。在此之前,结构体只有不完整类型。但是,结构体的定义要求除了柔性数组以外的所有成员都必须具有完整类型。

因此,在这个声明中

typedef struct node
{
    int data;
    struct node next; //changed this line
}Node; 

数据成员next具有不完整的类型。
来自C标准(6.7.2.1结构和联合说明符)
8. ...类型在终止列表的}之后立即变为不完整,此后变为完整。
并且
3 结构体或联合体不得包含不完整或函数类型的成员(因此,结构体不得包含自身的实例,但可以包含指向自身实例的指针),除了具有不完整数组类型的多个命名成员的结构体的最后一个成员;这样的结构体(以及包含可能递归地是这样的结构体成员的任何联合体)不得是结构体的成员或数组的元素。
至于指针,则它们始终具有完整的类型,因为它们的大小是已知的。

假设你有另一种类型的结构体的引用,那么使用指针会更好,因为否则该结构体将占用更多的空间。 - Alex Leibowitz
@AlexLeibowitz 这取决于上下文。例如,结构节点而不是标量数据成员数据可以包含一个结构类型的对象,例如人。 - Vlad from Moscow

1
实际上我们这样做是为了避免递归调用。以第二种情况为例,你在节点内部调用节点本身。那么节点的大小是多少?sizeof(int) + sizeof(node)。然后对于节点,大小再次变为sizeof(int) + sizeof(node)。因此,这是一个无法停止的递归过程。所以我们使用第一种情况来避免递归过程。它只是指向同类型结构体的对象。

1
编译器需要确定其处理对象的大小。
这需要完整定义,以便进行确定的计算。
在自引用结构的第一种情况中,我们有一个指针。指针是struct node *类型,由架构确定了明确的大小。
在第二种情况下 - struct node next,next的大小将是多少?它会是struct node的大小吗?好的,假设它是,但再次问一下 - struct node的大小是多少?嗯,答案是sizeof(int) + sizeof(struct node)。好吧,但再次...等等...什么?...回去重新读这整个段落,意识到这里的进退两难局面...
编译器不会也不欣赏这种情况!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接