C语言 自引用结构定义?

63lcw9qa  于 2023-06-21  发布在  其他
关注(0)|答案(9)|浏览(85)

我写C语言的时间不长,所以我不确定我应该如何去做这些递归的事情……我希望每个单元格都包含另一个单元格,但我得到了一个错误“field 'child' has incomplete type”。怎么了?

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

daupos2t1#

显然,一个Cell不能包含另一个Cell,因为它变成了一个永无止境的递归。
但是,Cell可以包含指向另一个Cell的指针。

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

gywdnpxw2#

在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;
}

虽然在标准中可能比这复杂得多,但你可以把它想象成编译器在typedef的第一行知道struct Cell,但直到最后一行才知道tCell:-)这就是我记得这个规则的原因。

muk1a3rh

muk1a3rh3#

从理论上讲,语言只能支持自指结构,不能支持自包含结构。

gj3fmq9x

gj3fmq9x4#

有一种方法可以解决这个问题:

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

struct Cell;
typedef struct Cell Cell;

如果你这样声明它,它会告诉编译器struct Cell和plain-ol '-cell是相同的。你可以像平常一样使用手机。但是,仍然必须在初始声明本身内部使用struct Cell。

bd1hkmkf

bd1hkmkf5#

我知道这篇文章已经很老了,但是,为了获得你正在寻找的效果,你可能想尝试以下内容:

#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;

在上面的代码片段中提到的两种情况下,你必须将你的子单元结构声明为指针。如果你不这样做,那么你会得到“字段'孩子'有不完整的类型”错误。原因是必须定义“struct Cell”,以便编译器在使用时知道分配多少空间。
如果你试图在“struct Cell”的定义中使用“struct Cell”,那么编译器还不能知道“struct Cell”应该占用多少空间。然而,编译器已经知道指针占用了多少空间,并且(通过forward声明)它知道“Cell”是“struct Cell”的一种类型(尽管它还不知道“struct Cell”有多大)。因此,编译器可以在正在定义的结构中定义“Cell *”。

t1qtbnec

t1qtbnec6#

预键入def结构,结构标记为:

//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;
tkclm6bt

tkclm6bt7#

让我们来看看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;

但最后一个选择增加一些额外的行和字与通常我们不想做的(我们是如此懒惰,你知道;))。所以更喜欢视图2。

cczfrluj

cczfrluj8#

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

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

eagi6jfj9#

前面所有的答案都很好,我只是想给予一个关于为什么一个结构不能包含它自己类型的示例(不是引用)的见解。
需要注意的是,结构体是“值”类型,也就是说,它们包含实际的值,所以当你声明一个结构体时,编译器必须决定给它的一个示例分配多少内存,所以它会遍历它的所有成员,并把它们的内存加起来,以计算出结构体的全部内存,但是如果编译器在内部发现了同一个结构体的一个示例,那么这就是一个悖论(也就是说,为了知道结构体A需要多少内存,你必须决定结构体A需要多少内存!).
但是引用类型是不同的,如果一个结构体'A'包含一个对它自己类型的示例的'引用',尽管我们还不知道有多少内存分配给它,我们知道有多少内存分配给一个内存地址(即引用)。
HTH

相关问题