web-dev-qa-db-ja.com

自己参照構造定義?

私は非常に長い間Cを書いていないので、これらの種類の再帰的なことをどのように行うべきかわからない...各セルに別のセルを含めるようにしたいが、それに沿ってエラーが発生する「フィールド「子」の型が不完全です」の行。調子はどう?

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

明らかに、セルは終わりのない再帰になるため、別のセルを含めることはできません。

ただし、Cellには別のセルへのポインターを含めることができます。

typedef struct Cell {
  bool isParent;
  struct Cell* child;
} Cell;
167
Andrew Grant

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を知らないコンパイラと考えることができます。最後の行:-)それは私がそのルールを覚えている方法です。

24
paxdiablo

理論的な観点から、言語は自己参照構造のみをサポートし、自己包含構造はサポートしません。

15
Sundar

これを回避する方法があります。

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

struct Cell;
typedef struct Cell Cell;

このように宣言すると、struct Cellとplain-ol'-cellが同じであることをコンパイラーに正しく伝えます。そのため、通常どおりCellを使用できます。ただし、初期宣言自体の内部でstruct Cellを使用する必要があります。

12

私はこの投稿が古いことを知っていますが、探している効果を得るには、次のことを試してください。

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

上記のコードフラグメントで言及した2つのケースのいずれかでは、子のCell構造体をポインターとして宣言する必要があります。そうしないと、「フィールド「子」の型が不完全です」というエラーが表示されます。その理由は、コンパイラーが使用時に割り当てるスペースを知るために、「struct Cell」を定義する必要があるためです。

「struct Cell」の定義内で「struct Cell」を使用しようとすると、コンパイラーは「struct Cell」がどれだけのスペースを取るかをまだ知ることができません。ただし、コンパイラーは、ポインターがどのくらいのスペースを使用するかをすでに知っており、(前方宣言で)「Cell」が「struct Cell」のタイプであることを知っています(「struct Cell」の大きさはまだわかりませんが) )。そのため、コンパイラは、定義されている構造内に「Cell *」を定義できます。

8
Shawn

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をお勧めします。

3
vineetv2821993

別の便利な方法は、構造タグを次のように事前に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;
2
Keynes

それ自体への参照を含む構造。リンクリストのノードを記述する構造でこれがよく発生します。各ノードには、チェーン内の次のノードへの参照が必要です。

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

これまでの答えはすべて素晴らしいです。構造にそれ自体の型のインスタンス(参照ではない)を含めることができない理由についての洞察を提供したいと考えました。

構造体は「値」型、つまり実際の値を含むことに注意することが非常に重要です。したがって、構造体を宣言するとき、コンパイラはそのインスタンスに割り当てるメモリ量を決定する必要があります。構造体のすべてのメモリを把握するためにメモリを増やしますが、コンパイラが内部に同じ構造体のインスタンスを見つけた場合、これは逆説です(つまり、構造体Aがどれだけのメモリを持っているかを知るために、構造体Aは!)を取ります。

しかし、参照型は異なります。構造体「A」にそれ自身の型のインスタンスへの「参照」が含まれている場合、まだどのくらいのメモリが割り当てられているかはわかりませんが、メモリにどれだけのメモリが割り当てられているかはわかりますアドレス(つまり、参照)。

HTH

1
m.eldehairy