Самореферентное определение структуры?

Я не писал C очень долго, и поэтому я не уверен, как я должен заниматься такими рекурсивными вещами... Я бы хотел, чтобы каждая ячейка содержала другую ячейку, но я получаю сообщение об ошибке строки "поля" ребенок "имеют неполный тип". Что?

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

Ответ 1

Очевидно, что ячейка не может содержать другую ячейку, поскольку она становится бесконечной рекурсией.

Однако Cell CAN содержит указатель на другую ячейку.

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

Ответ 2

В 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 до последней строки :-) То, как я помню это правило,

Ответ 3

С теоретической точки зрения Языки могут поддерживать только самореферентные структуры, а не самосознающие структуры.

Ответ 4

В этом есть способ:

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

struct Cell;
typedef struct Cell Cell;

Если вы объявляете это так, он правильно сообщает компилятору, что структура Cell и plain-ol'-cell одинаковы. Таким образом, вы можете использовать Cell как обычно. Тем не менее все равно придется использовать struct Cell внутри самого исходного объявления.

Ответ 5

Я знаю, что этот пост старый, однако, чтобы получить эффект, который вы ищете, вы можете попробовать следующее:

#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" . Однако компилятор уже знает, сколько пробелов занимает указатель, и (с помощью прямого объявления) он знает, что "Cell" - это тип "struct Cell" (хотя он еще не знает, насколько велика "ячейка структуры" ). Таким образом, компилятор может определить "Ячейку" в структуре, которая определяется.

Ответ 6

Давайте рассмотрим базовое определение 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.

Ответ 7

A Структура, содержащая ссылку на себя. Общее появление этого в структуре, которая описывает node для списка ссылок. Каждой node нужна ссылка на следующий node в цепочке.

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

Ответ 8

Другим удобным способом является предварительная настройка структуры с тегом структуры как:

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

Ответ 9

Все предыдущие ответы велики, я просто подумал, чтобы дать понять, почему структура не может содержать экземпляр своего типа (а не ссылку).

очень важно отметить, что структуры являются "ценностными" типами, то есть они содержат фактическое значение, поэтому, когда вы объявляете структуру, компилятор должен решить, сколько памяти выделяется экземпляру, поэтому он проходит через все свои членов и добавляет свою память, чтобы вычислить всю память структуры, но если компилятор обнаружил экземпляр одной и той же структуры внутри, то это парадокс (т.е. чтобы узнать, сколько памяти struct A вам нужно решить сколько памяти struct A занимает!).

Но ссылочные типы различны, если структура 'A' содержит ссылку на экземпляр своего типа, хотя мы еще не знаем, сколько памяти выделено для нее, мы знаем, сколько памяти выделено на адрес памяти (например, ссылку).

НТН