[c] 자기 참조 구조체 정의?

나는 오랫동안 C를 작성하지 않았으므로 이러한 종류의 재귀 적 일을 어떻게 해야하는지 잘 모르겠습니다 … 각 셀에 다른 셀이 포함되도록하고 싶지만 오류가 발생합니다. “필드 ‘자식’에 불완전한 유형이 있습니다.” 뭐야?

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



답변

셀은 끝없는 재귀가되므로 다른 셀을 포함 할 수 없습니다.

그러나 셀은 다른 셀에 대한 포인터를 포함 할 수 있습니다.

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


답변

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마지막 줄까지는 알지 못하는 컴파일러라고 생각할 수 있습니다 .


답변

이론적 관점에서 언어는 자체 포함 구조가 아닌 자체 참조 구조 만 지원할 수 있습니다.


답변

이 문제를 해결하는 방법이 있습니다.

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

struct Cell;
typedef struct Cell Cell;

이렇게 선언하면 컴파일러에게 struct Cell과 plain-ol’-cell이 동일하다는 것을 올바르게 알립니다. 따라서 평소처럼 Cell을 사용할 수 있습니다. 그래도 초기 선언 자체에서 struct Cell을 사용해야합니다.


답변

이 게시물이 오래되었다는 것을 알고 있지만 원하는 효과를 얻으려면 다음을 시도해보십시오.

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

위의 코드 조각에서 언급 한 두 경우 중 하나에서 반드시 자식 셀 구조를 포인터로 선언해야합니다. 그렇지 않으면 “field ‘child’has complete type”오류가 발생합니다. 그 이유는 컴파일러가 사용될 때 할당 할 공간의 양을 알기 위해 “struct Cell”을 정의해야하기 때문입니다.

“struct Cell”의 정의 내에서 “struct Cell”을 사용하려고하면 컴파일러에서 “struct Cell”이 차지하는 공간을 아직 알 수 없습니다. 그러나 컴파일러는 포인터가 차지하는 공간을 이미 알고 있으며 (앞으로 선언하면) “Cell”이 “struct Cell”의 유형이라는 것을 알고 있습니다 (아직 “struct Cell”의 크기는 아직 알지 못합니다) ). 따라서 컴파일러는 정의중인 구조체 내에서 “Cell *”을 정의 할 수 있습니다.


답변

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를 선호하십시오.


답변

또 다른 편리한 방법은 다음과 같이 구조 태그를 사용하여 구조를 미리 typedef하는 것입니다.

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