malloc は、最初にポインターの配列を割り当てる必要があることをどのように認識しているのでしょうか。各ポインターは 1 次元配列を指しています。
そうではありません。malloc
指定したバイト数を割り当てるだけで、それらのバイトがどのように集約データ型に構造化されているかについての実用的な知識はありません。
多次元配列を動的に割り当てようとしている場合、いくつかの選択肢があります。
可変長配列をサポートする C99 または C2011 コンパイラを使用している場合は、単に配列を次のように宣言できます。
int rows;
int cols;
...
rows = ...;
cols = ...;
...
int array[rows][cols];
ただし、VLA には多くの問題があります。非常に大きな配列では機能しない、ファイル スコープで宣言できない、などです。
二次的なアプローチは、次のようなことを行うことです。
int rows;
int cols;
...
rows = ...;
cols = ...;
...
int (*arrayPtr)[cols] = malloc(sizeof *arrayPtr * rows);
この場合、はwith要素arrayPtr
の配列へのポインタとして宣言されているため、それぞれ要素の配列を割り当てています。;と書くだけで各要素にアクセスできることに注意してください。ポインター演算の規則は、通常の 2D 配列と同じように機能します。 int
cols
rows
cols
arrayPtr[i][j]
VLA をサポートする C コンパイラを使用していない場合は、別のアプローチを取る必要があります。
すべてを単一のチャンクとして割り当てることができますが、次のようにオフセットを計算して、1 次元配列としてアクセスする必要があります。
int *arrayPtr = malloc(sizeof *arrayPtr * rows * cols);
...
arrayPtr[i * rows + j] = ...;
または、次の 2 つのステップで割り当てることもできます。
int **arrayPtr = malloc(sizeof *arrayPtr * rows);
if (arrayPtr)
{
int i;
for (i = 0; i < rows; i++)
{
arrayPtr[i] = malloc(sizeof *arrayPtr[i] * cols);
if (arrayPtr[i])
{
int j;
for (j = 0; j < cols; j++)
{
arrayPtr[i][j] = some_initial_value();
}
}
}
}