私は長い間Cを書いていないので、このような種類の再帰的な処理をどのように行えばよいのかわかりません...各セルに別のセルを含めたいのですが、エラーが発生します「フィールド「子」の型が不完全です」の行。調子はどう?
typedef struct Cell {
int isParent;
Cell child;
} Cell;
私は長い間Cを書いていないので、このような種類の再帰的な処理をどのように行えばよいのかわかりません...各セルに別のセルを含めたいのですが、エラーが発生します「フィールド「子」の型が不完全です」の行。調子はどう?
typedef struct Cell {
int isParent;
Cell child;
} Cell;
回答:
明らかに、セルは他のセルを含むことはできません。それが終わることのない再帰になるからです。
ただし、セルには別のセルへのポインタを含めることができます。
typedef struct Cell {
bool isParent;
struct Cell* child;
} Cell;
Cell
まだ対象範囲外です。
Cell*
れcell->child
ます。
struct
Cでsは基本的に互いに隣接してそれらの値のすべてをストア(その構造体は無限のサイズのメモリ構造をもたらす、別のものを含有し、そうでなければならないので)、実際にそれ自体で構造体を格納することは不可能です。
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を使用する必要があります。
struct Cell;
また書きましたか?
struct Cell
。
struct Cell;
冗長性が生じます。ただし、何らかの理由で最後の2行をヘッダーファイルに入れ、最初の4行で構造体を定義する前にインクルードする場合は、余分なものが必要です。Cell
struct Cell;
typedef struct Cell Cell;
、それが作るCell
の別名をstruct 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;
上記のコードフラグメントで言及した2つのケースのいずれかで、子Cell構造体をポインターとして宣言する必要があります。そうしないと、「フィールド '子'の型が不完全です」というエラーが発生します。その理由は、コンパイラーが使用されるときに割り振るスペースの量をコンパイラーが知るためには、「struct Cell」を定義する必要があるためです。
「struct 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
構文の説明が正しくありません(たとえばtypedef int (*foo)(void);
)。ビュー1とビュー2の例は機能しません。これらstruct Cell
は不完全な型になるため、実際にchild
コードで使用することはできません。
もう1つの便利な方法は、次のように構造体タグで構造体を事前に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;
以前のすべての答えは素晴らしいですが、構造体が独自のタイプのインスタンス(参照ではない)を含むことができない理由についての洞察を提供することを考えました。
構造体は「値」型であることに注意することが非常に重要です。つまり、構造体には実際の値が含まれるため、構造体を宣言する場合、コンパイラーはインスタンスに割り当てるメモリ量を決定する必要があるため、すべてのメンバーを調べて追加します。構造体のすべてのメモリを把握するためにメモリを増やしますが、コンパイラが同じ構造体のインスタンスを内部で見つけた場合、これはパラドックスです(つまり、構造体Aが使用するメモリの量を知るには、メモリの量を決定する必要があります) struct Aは!)をとります。
しかし、参照型は異なります。構造体「A」がそれ自体の型のインスタンスへの「参照」を含む場合、それに割り当てられているメモリの量はまだわかりませんが、メモリに割り当てられているメモリの量はわかりますアドレス(つまり、参照)。
HTH