自引用结构定义?

时间:2009-02-26 00:47:06

标签: c recursion struct typedef

我没有写C很长时间,所以我不确定我应该怎么做这些递归的东西...我希望每个单元格包含另一个单元格,但我得到一个“field'child''的错误是”类型不完整“。怎么了?

typedef struct Cell {
  int isParent;
  Cell child;
} Cell;

9 个答案:

答案 0 :(得分:163)

显然,Cell不能包含另一个单元格,因为它变成永无止境的递归。

但是,Cell CAN包含指向另一个单元格的指针。

typedef struct Cell {
  bool isParent;
  struct Cell* child;
} Cell;

答案 1 :(得分:22)

在C中,您无法使用结构本身引用您正在创建的typedef。您必须使用结构名称,如以下测试程序中所示:

#include <stdio.h>
#include <stdlib.h>

typedef struct Cell {
  int cellSeq;
  struct Cell* next; /* 'tCell *next' will not work here */
} tCell;

int main(void) {
    int i;
    tCell *curr;
    tCell *first;
    tCell *last;

    /* Construct linked list, 100 down to 80. */

    first = malloc (sizeof (tCell));
    last = first;
    first->cellSeq = 100;
    first->next = NULL;
    for (i = 0; i < 20; i++) {
        curr = malloc (sizeof (tCell));
        curr->cellSeq = last->cellSeq - 1;
        curr->next = NULL;
        last->next = curr;
        last = curr;
    }

    /* Walk the list, printing sequence numbers. */

    curr = first;
    while (curr != NULL) {
        printf ("Sequence = %d\n", curr->cellSeq);
        curr = curr->next;
    }

    return 0;
}

虽然它可能比标准中的要复杂得多,但您可以将其视为编译器在struct Cell的第一行知道typedef但不知道tCell的情况。直到最后一行:-)这就是我记得那条规则的方式。

答案 2 :(得分:15)

从理论的角度来看,语言只能支持自我指涉的结构而不是自我包容的结构。

答案 3 :(得分:12)

有一种解决方法:

struct Cell {
  bool isParent;
  struct Cell* child;
};

struct Cell;
typedef struct Cell Cell;

如果你这样声明,它会正确告诉编译器struct cell和plain-ol'-cell是相同的。所以你可以像平常一样使用Cell。尽管如此,仍然必须在初始声明中使用struct Cell。

答案 4 :(得分:8)

我知道这篇文章已经过时了,为了获得您想要的效果,您可能需要尝试以下方法:

#define TAKE_ADVANTAGE

/* Forward declaration of "struct Cell" as type Cell. */
typedef struct Cell Cell;

#ifdef TAKE_ADVANTAGE
/*
   Define Cell structure taking advantage of forward declaration.
*/
struct Cell
{
   int isParent;
   Cell *child;
};

#else

/*
   Or...you could define it as other posters have mentioned without taking
   advantage of the forward declaration.
*/
struct Cell
{
   int isParent;
   struct Cell *child;
};

#endif

/*
    Some code here...
*/

/* Use the Cell type. */
Cell newCell;

在上面代码片段中提到的两种情况中的任何一种情况下,您必须将您的子Cell结构声明为指针。如果你不这样做,那么你将得到“字段'子'具有不完整类型”错误。原因是必须定义“struct Cell”,以便编译器知道在使用它时要分配多少空间。

如果您尝试在“struct Cell”的定义中使用“struct Cell”,那么编译器还不能知道“struct Cell”应该占用多少空间。但是,编译器已经知道指针占用了多少空间,并且(使用前向声明)它知道“Cell”是一种“struct Cell”(尽管它还不知道“struct Cell”有多大) )。因此,编译器可以在正在定义的结构中定义“Cell *”。

答案 5 :(得分:3)

让我们来看看typedef的基本定义。 typedef用于定义现有数据类型的别名,无论是用户定义的还是内置的。

typedef <data_type> <alias>;

例如

typedef int scores;

scores team1 = 99;

这里的混淆是自引用结构,因为同一数据类型的成员之前没有定义。因此,以标准方式,您可以将代码编写为: -

//View 1
typedef struct{ bool isParent; struct Cell* child;} Cell;

//View 2
typedef struct{
  bool isParent;
  struct Cell* child;
} Cell;

//Other Available ways, define stucture and create typedef
struct Cell {
  bool isParent;
  struct Cell* child;
};

typedef struct Cell Cell;

但是最后一个选项增加了一些额外的行和单词通常我们不想做(我们很懒,你知道;))。所以更喜欢View 2。

答案 6 :(得分:2)

另一种方便的方法是使用结构标记预先键入结构:

//declare new type 'Node', as same as struct tag
typedef struct Node Node;
//struct with structure tag 'Node'
struct Node
{
int data;
//pointer to structure with custom type as same as struct tag
Node *nextNode;
};
//another pointer of custom type 'Node', same as struct tag
Node *node;

答案 7 :(得分:1)

包含对自身的引用的结构。在描述链接列表的节点的结构中常见的情况。每个节点都需要引用链中的下一个节点。

struct node
{
       int data;
       struct node *next; // <-self reference
};

答案 8 :(得分:1)

以前的所有答案都很棒,我只想深入了解一个结构为什么不能包含自己类型的实例(不是参考)。

非常重要的是要注意结构的价值和价值。类型,即它们包含实际值,所以当你声明一个结构时,编译器必须决定分配给它的一个实例多少内存,所以它通过它的所有成员并加上它们的内存来计算出所有的内存。结构,但如果编译器发现内部相同结构的实例,则这是一个悖论(即,为了知道结构A需要多少内存,你必须决定结构A需要多少内存!)。

但是参考类型是不同的,如果结构&#39; A&#39;包含&#39;参考&#39;虽然我们还不知道分配了多少内存,但我们知道有多少内存被分配给内存地址(即引用)。

HTH