2016-09-23 8 views
0

これらの構造体へのポインタのリストの中間配列を作成せずに構造体の配列を初期化するにはどうすればよいですか?私はsturctsをshape_tへのポインタの配列を指すように.elementsメンバーが必要ですが、このコードはコンパイルされません構造体へのポインタの配列を初期化

snippets $ cat a2p.c 
struct shape { 
    int  angles; 
    char shape_name[16]; 
}; 
typedef struct shape shape_t; 
struct container { 
    char   name[32]; 
    shape_t   **elements; 
    int    num_elts; 
}; 
typedef struct container container_t; 

shape_t triangle = { 
    .angles  = 3, 
    .shape_name = {"Triangle"} 
}; 
shape_t rectangle = { 
    .angles  = 4, 
    .shape_name = {"Rectangle"} 
}; 

container_t c = { 
    .name  = {"Case"}, 
    .elements = { 
     &triangle, 
     &rectangle 
    }, 
    .num_elts =2 
}; 


int main(void) { 

    return 0; 

}  

snippets $ gcc -c a2p.c 
a2p.c:24:2: warning: braces around scalar initializer 
    .elements = { 
^
a2p.c:24:2: note: (near initialization for ‘c.elements’) 
a2p.c:25:3: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types] 
    &triangle, 
^
a2p.c:25:3: note: (near initialization for ‘c.elements’) 
a2p.c:26:3: warning: excess elements in scalar initializer 
    &rectangle 
^
a2p.c:26:3: note: (near initialization for ‘c.elements’) 
snippets $ 

しかし、私が追加した場合、次のコード例を考えてみましょうこのような中間配列:

shape_t *shapes[] = { 
    &triangle, 
    &rectangle 
}; 
container_t c = { 
    .name  = {"Case"}, 
    .elements = shapes, 
    .num_elts =2 
}; 

コードはokです。中間のステップとしてshapes []配列を作成し、最初のコードスニペットのようにすべてのデータを直接container_tを初期化するのを避けることはできますか?その後、正しい初期化構文は何でしょうか?

+0

'elements'は、構造体の配列ではなく、ポインタの配列へのポインタです。 – Barmar

+0

配列とポインタは同じものではありません。配列は特定のコンテキストではポインタへと減衰しますが、初期化リストでは配列リテラルは減衰しません。 – Barmar

+0

@Barmar私がメモリ内に構築したい階層の種類を理解していて、その答えを知っていれば、それを分けてください。 TIA – Nulik

答えて

2

あなたはほぼそこにいます。あなただけのように、elements初期化子は、適切なポインタであることを確認する必要があります

struct shape { 
    int  angles; 
    char shape_name[16]; 
}; 
typedef struct shape shape_t; 
struct container { 
    char   name[32]; 
    shape_t   **elements; 
    int    num_elts; 
}; 
typedef struct container container_t; 

shape_t triangle = { 
    .angles  = 3, 
    .shape_name = { "Triangle" } 
}; 
shape_t rectangle = { 
    .angles  = 4, 
    .shape_name = { "Rectangle" } 
}; 

container_t c = { 
    .name  = { "Case" }, 
    .elements = (shape_t *[]) { 
     &triangle, 
     &rectangle, 
    }, 
    .num_elts = 2, 
}; 

int main(void) { 
    return 0; 
} 

shape_t要素へのポインタの配列のリテラルの化合物の使用に注意してください。

+0

ありがとう!それはまさに私が必要としていたものです。このような深いレベルでCを理解するためには、どのような本を読んでお勧めしますか? – Nulik

+0

私が言ったように、あなたはほとんどそこにいました。穴のいくつかを埋めるために読むのに良い本として[C:A Reference Manual](http://www.careferencemanual.com/)をお勧めしますが、指定されたイニシャライザ、あなたが見逃したギャップは、化合物リテラルをどのように組み合わせて使用​​するかということでした。 –

1

2番目のスニペットで行ったのとまったく同じようにする必要があります。 elementsをのようにshape_t *の配列として宣言した場合、1つの初期化ですべてを行うことができる唯一の方法ですが、そこでは固定サイズの配列を持つことはおそらくありません。

1

あなたはその後、C99で次のように使用することができ、以降、コンパイラ構造定義の最後に要素のメンバーを移動した場合:

container_t c2 = { 
    .name  = {"Case2"}, 
    .num_elts =3, 
    .elements = { 
     &(shape_t){ 3, "Triangle" } , 
     &(shape_t){ 4, "Rectangle" }, 
     &(shape_t){ 2, "Line" } 
    } 
};

可変サイズのメンバーは、構造体の最後のメンバーである必要があります。今

container_t c2 = { 
    .name  = {"Case2"}, 
    .elements = { 
     &(shape_t){ 3, "Triangle" } , 
     &(shape_t){ 4, "Rectangle" }, 
     &(shape_t){ 2, "Line" }, 
     NULL 
    } 
};

あなただけ:

簡単にバグのために場所を嫌って、私の一部は、あなたがNULLポインタでリストを終了し、num_eltsをドロップして手動で設定要素数の必要性を取り除くことができますノートリストを一歩進んでNULL == container_list->elements[n]

関連する問題