3

私はcにかなり慣れていないので、私の手順が間違っている場合はお知らせください。次のようなものがあるとしましょう。

struct graphNode{
    int val;
    graphNode* parent;
    int succSize;
    int succMaxSize;
    graphNode* succ[1];
};

以下を使用して新しいノードを作成します。

graphNode *n;
n = malloc(sizeof(struct graphNode));
assert(n);
n->val = 1;
n->parent = NULL;
n->succSize = 0;
n->succMaxSize = 1;

次に、ノードに後継者を追加したい場合

if (n->succSize == n->succMaxSize){
    n->succ = realloc(n->succ, sizeof(graphNode*) * n->succMaxSize * 2);
    n->succMaxSize *= 2;
} 
n->succ[succSize] = n2; //n2 is of type graphNode*
succSize++;

これは正しいです?構造体にも再割り当てする必要がありますか、それとも配列の再割り当てで十分ですか? 初期配列に対して malloc する必要がありますか? n の malloc 呼び出しに初期配列サイズを含める必要がありますか?

4

5 に答える 5

7

C で「伸縮性のある」配列メンバーを定義する通常の方法は、サイズを指定するか、サイズを0まったく指定しないことです。次に例を示します。

struct foo {
    int stuff;
    bar theBars[]; // or theBars[0]
};

この定義により、sizeof(struct foo)は最後に配列以外のすべての要素を含め、 と言って適切なサイズを割り当てることができますmalloc(sizeof(struct foo) + numberOfBars * sizeof(bar))

bar要素の数を変更するために再割り当てする必要がある場合は、同じ式を使用します (ただし、 new を使用しますnumberOfBars)。

明確にするために、構造体の一部だけにすることはできませんrealloc。あなたはreallocすべてをしなければなりません。

于 2013-10-17T22:09:15.303 に答える
1

通常、最後のフィールドがサイズ 0 または 1 の配列である構造体定義を見ると、構造体が malloc されているときに、作成者が malloc で微妙なことを行うことを意味します。

例えば

struct foo {
   int x;
   :
   : 
   type a[0];
};

のようなmallocで

  struct foo *p = malloc(sizeof(*p) + (n * sizeof(type));

これが行うことは、構造体と末尾の配列に連続したメモリのチャンクを割り当てることです。この場合、配列サイズは n です。したがって、この場合の配列への参照は次のとおりです。

p->a[i] // where i >= 0 and i < n

これを行う理由の 1 つは、メモリを節約することです。

これについては、StackOver にもっと詳しい説明があるはずです。これは非常に一般的な C イディオムです。

通常、配列が動的な場合は使用されません。むしろ、malloc() 時に配列サイズがわかっている場合に使用されます。もちろん、動的に使用できますが、構造体や配列だけでなく、メモリ チャンク全体を再割り当てする必要があります。サイズを 2n に増やすには、次のようにします。

  p = realloc(p, sizeof(*p) + (2 * n * sizeof(type)));

これで、配列は以前の 2 倍になりましたが、それでもメモリの 1 つのチャンクです。

于 2013-10-17T22:38:56.977 に答える
0

私もCは初めてですが、すぐにわかることがいくつかあります。まず、配列を再割り当てすることはできません。c89 では、コンパイル時の固定サイズです。C99 と C11 では、動的に割り当てることはできますが、再割り当てすることはできません (私の知る限り)。したがって、このためには、

graphnode *succ; 

ポインター、および malloc(nodes * sizeof(node))。

graphNode* succ[1];

これにより、最大インデックスが 1 の配列ではなく、サイズが 1 の配列が作成されます。したがって、機能的には(ほぼ)同じです

graphNode* succ;

ただし、作成後にサイズを変更することはできません。

あなたが望むのは、動的に再割り当て可能な量のブランチを持つツリーを作成することだと思います。この場合、graphNode* ポインターのサイズを再割り当てするだけで済み、配列の場合と同様にインデックスを介して各要素にアクセスできます。

于 2013-10-17T22:06:00.810 に答える
0

単一の配列のみが必要な場合はsucc、単一のポインターを作成し、malloc/realloc などを使用して配列にメモリを割り当てます。

graphNode* succ;

あなたがしていることは、ほぼ確実に壊れます。

于 2013-10-17T22:03:01.413 に答える