자기 참조 구조체 정의?


134

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

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

9
PS는 사실은 (일반적인 패턴이다) "셀"을 "구조체 셀"타입 정의
데이비드 Z

아마 C ++ 컴파일러를 사용하고있을 것입니다. 또한 실제로 C라면 _Bool을 사용해야합니다.
nabiy

실제로 C :-) 인 경우 int를 사용해야합니다.
paxdiablo

2
왜? C99에 부울이 있습니다-<stdbool.h> 만 포함하면됩니다
Jonathan Leffler

답변:


184

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

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

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

7
@ cs01 아니요, Cell아직 범위 내에 없습니다.
fredoverflow

1
그것은 것입니다 의미합니다. 파이썬은 그것을 허용하고 심지어 그러한 객체의 직렬화를 허용합니다. 왜 C ++이 아닌가?
noɥʇʎԀʎzɐɹƆ

1
내가 할당하려고 할 때 경고를 얻을 Cell*cell->child.
Tomáš Zato-복원 모니카

3
@ noɥʇʎԀʎzɐɹƆ 파이썬은 포인터를 알아 채지 못하도록 포인터를 추상화하기 때문에. 이후 structC에서의이 기본적으로 그냥 서로 옆에 자신의 모든 값을 저장, (무한 크기의 메모리 구조로 이어지는, 그 구조체는 너무 다른 하나를 포함해야하기 때문에) 실제로 그 자체로 구조체를 저장하는 것은 불가능하다 .
재즈 피

1
의 사용법에 대한 설명 struct Cell이 답변을 참조하십시오 .
wizzwizz4

26

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


c ++에 대한 당신은 c ++에 관한 답변을 링크하십시오
rimalonfire

@rimiro, 질문은 C였습니다. 당신이 C ++ 변형에 대한 답을 원한다면, 당신은해야 묻는 질문으로.
paxdiablo

16

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


실제적인 관점에서 볼 때, 그러한 'struct Cell'인스턴스는 실제로 얼마나 클 것인가?
Marsh Ray

26
대부분의 컴퓨터에서 자체보다 4 바이트 더 큽니다.
TonyK

13

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

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

struct Cell;
typedef struct Cell Cell;

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


9
struct Cell;다시 쓰 셨어요?
MAKZ

@MAKZ는의 정의를 컴파일 할 때 컴파일러가 typedef를 실행하지 않았기 때문입니다 struct Cell.
Tyler Crompton

2
@TylerCrompton 위의 코드 블록을 단일 C 소스 파일에 넣으면 typedef "컴파일러에 의해 실행"되어 여분의 여분이 만들어 struct Cell;집니다. 그러나, 어떤 이유로 당신이 포함 헤더 파일에 마지막 두 줄 넣으면 전에 당신이 정의 Cell처음 네 라인 구조체를, 다음 여분는 struct Cell;nececairy입니다.
yyny

C99 표준에서는 컴파일되지 않습니다.
Tomáš Zato-복원 모니카

2
@YoYoYonnY 아니요, 여전히 쓸 typedef struct Cell Cell;Cell있으며에 대한 별칭을 struct Cell만듭니다. 컴파일러가 struct Cell { .... }이전에 본 적이 있는지 여부는 중요하지 않습니다 .
melpomene

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;

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

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


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;

그러나 마지막 옵션은 일반적으로 원하지 않는 여분의 줄과 단어를 증가시킵니다 (우리는 너무 게으르다;)). 따라서보기 2를 선호하십시오.


typedef구문에 대한 설명 이 잘못되었습니다 (예 :) typedef int (*foo)(void);. View 1 및 View 2 예제가 작동하지 않습니다. struct Cell불완전한 유형을 만들 므로 실제로 child코드에서 사용할 수 없습니다 .
melpomene

3

또 다른 편리한 방법은 다음과 같이 구조 태그를 사용하여 구조를 미리 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;

1

자체에 대한 참조를 포함하는 구조입니다. 링크 목록에 대한 노드를 설명하는 구조에서 일반적으로 발생합니다. 각 노드는 체인의 다음 노드에 대한 참조가 필요합니다.

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

1

이전의 모든 대답은 훌륭합니다. 구조에 왜 자체 유형의 인스턴스 (참조가 아닌)를 포함 할 수 없는지에 대한 통찰력을 제공한다고 생각했습니다.

구조는 '값'유형이라는 점에 유의해야합니다. 즉, 실제 값을 포함하므로 구조를 선언 할 때 컴파일러는 인스턴스에 할당 할 메모리 양을 결정해야하므로 모든 멤버를 거치고 추가됩니다. 구조체의 모든 메모리 전체를 알아 내기 위해 메모리를 늘리십시오.하지만 컴파일러가 동일한 구조체의 인스턴스를 내부에서 발견하면 역설입니다 (즉, 구조체 A가 얼마나 많은 메모리를 필요로하는지 알기 위해서는 메모리 양을 결정해야합니다) struct A가 걸립니다!).

그러나 구조체 'A'에 자체 유형의 인스턴스에 대한 '참조'가 포함되어 있으면 참조 유형이 다릅니다. 아직 할당 된 메모리의 양을 모르지만 메모리에 할당 된 메모리의 양을 알고 있습니다 주소 (예 : 참조).

HTH

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.