Cで静的配列の動的配列をどのように指定しますか?
静的配列の 2 つの動的配列を保持する構造体を作成したいと考えています。
struct indexed_face_set {
double * [3] vertices;
int * [3] faces;
};
これは、それぞれ 3 つの double である頂点の動的リストと、それぞれ 3 つの int である面の動的リストを保持する必要があります。
Cで静的配列の動的配列をどのように指定しますか?
静的配列の 2 つの動的配列を保持する構造体を作成したいと考えています。
struct indexed_face_set {
double * [3] vertices;
int * [3] faces;
};
これは、それぞれ 3 つの double である頂点の動的リストと、それぞれ 3 つの int である面の動的リストを保持する必要があります。
構文は、まあ、C の宣言へのアプローチは最もクリーンではなく、C++ はそれを継承しています...
double (*vertices)[3];
その宣言は、それがオブジェクトvertices
へのポインタであることを意味しdouble [3]
ます。かっこが必要であることに注意してください。そうしないと ( のようにdouble *vertices[3]
) 3 の配列を意味しdouble*
ます。
しばらくすると、式の括弧の逆の方法に慣れてきます...
それぞれが次元 3 の 2 つの配列を含む構造体の特定のケースでは、配列を動的に個別に割り当てるよりも、配列を構造体の一部にする方が簡単です。
struct indexed_face_set
{
double vertices[3];
int faces[3];
};
ただし、動的な配列割り当てを処理することが理にかなっている場合もあります。その場合、構造内の配列へのポインターが必要です (ポインターの配列ではありません)。したがって、次のように記述する必要があります。
struct indexed_face_set
{
double (*vertices)[3];
int (*faces)[3];
};
完全な を割り当てるには、次のstruct indexed_face_set
ようなものを使用するnew_indexed_face_set()
必要があり、解放するには、次のようなものを使用する必要がありますdestroy_indexed_face_set()
。
struct indexed_face_set *new_indexed_face_set(void)
{
struct indexed_face_set *new_ifs = malloc(sizeof(*new_ifs));
if (new_ifs != 0)
{
double (*v)[3] = malloc(sizeof(*v));
int (*f)[3] = malloc(sizeof(*f));
if (v == 0 || f == 0)
{
free(v);
free(f);
free(new_ifs);
new_ifs = 0;
}
else
{
new_ifs->vertices = v;
new_ifs->faces = f;
}
}
return(new_ifs);
}
void destroy_indexed_face_set(struct indexed_face_set *ifs)
{
if (ifs != 0)
{
free(ifs->vertices);
free(ifs->faces);
free(ifs);
}
}
次に、次のように使用できます。
void play_with_ifs(void)
{
struct indexed_face_set *ifs = new_indexed_face_set();
if (ifs != 0)
{
(*ifs->vertices)[0] = 3.14159;
(*ifs->vertices)[1] = 2.71813;
(*ifs->vertices)[2] = 1.61803;
(*ifs->faces)[0] = 31;
(*ifs->faces)[1] = 30;
(*ifs->faces)[2] = 29;
do_something_fancy(ifs);
destroy_indexed_face_set(ifs);
}
}
配列へのポインターを使用する表記はやや乱雑であることに注意してください。人々がそれらを頻繁に使用しない理由の1つ。
このフラグメントをヘッダーの本文として使用できます。
#ifndef DASS_H_INCLUDED
#define DASS_H_INCLUDED
struct indexed_face_set;
extern void play_with_ifs(void);
extern void do_something_fancy(struct indexed_face_set *ifs);
extern void destroy_indexed_face_set(struct indexed_face_set *ifs);
extern struct indexed_face_set *new_indexed_face_set(void);
#endif /* DASS_H_INCLUDED */
追加のヘッダーを含める必要はありません。これらの関数の構造定義の詳細は必要ありません。適切なヘッダー ガードでラップします。
上記のコードは、配列の使用に関しては少し面倒なので、ほとんどの人はより単純な表記法を使用します。上記のヘッダーは変更しないでおくことができますが、コードは次のように変更できます。
struct indexed_face_set
{
double *vertices;
int *faces;
};
struct indexed_face_set *new_indexed_face_set(void)
{
struct indexed_face_set *new_ifs = malloc(sizeof(*new_ifs));
if (new_ifs != 0)
{
double *v = malloc(3 * sizeof(*v));
int *f = malloc(3 * sizeof(*f));
if (v == 0 || f == 0)
{
free(v);
free(f);
free(new_ifs);
new_ifs = 0;
}
else
{
new_ifs->vertices = v;
new_ifs->faces = f;
}
}
return(new_ifs);
}
void destroy_indexed_face_set(struct indexed_face_set *ifs)
{
if (ifs != 0)
{
free(ifs->vertices);
free(ifs->faces);
free(ifs);
}
}
void play_with_ifs(void)
{
struct indexed_face_set *ifs = new_indexed_face_set();
if (ifs != 0)
{
ifs->vertices[0] = 3.14159;
ifs->vertices[1] = 2.71813;
ifs->vertices[2] = 1.61803;
ifs->faces[0] = 31;
ifs->faces[1] = 30;
ifs->faces[2] = 29;
do_something_fancy(ifs);
destroy_indexed_face_set(ifs);
}
}
これは、理解と使用がはるかに簡単であり、一般に、より慣用的な C と見なされます。
各配列のサイズは固定であるため、構造体にサイズを記録する必要は特にありません。実行時にサイズが変化する場合、特にいくつかのインデックス付きの面セットが、たとえば 8 つの頂点と 6 つの面 (直方体?) を持っている場合は、配列のサイズを構造体に記録することをお勧めします。への呼び出しで、頂点の数と面の数も指定しますnew_indexed_face_set()
。