2
int **arrayPtr; 
arrayPtr = malloc(sizeof(int) * rows *cols + sizeof(int *) * rows);

malloc上記のコードでは、1回の呼び出し で2D配列を割り当てようとしています。mallocいくつかのバイトを取り、その数のバイトにメモリを割り当てますが、上記の場合、malloc最初にポインタの配列を割り当てる必要があることをどのようにして知ることができますか?各ポインタは1次元配列を指します。

mallocこの特定のケースでは、内部でどのように機能しますか?

4

5 に答える 5

5

2D 配列は、配列へのポインターの配列と同じではありません。

int **arrayPtr2D 配列を定義しません。2D 配列は次のようになります。

int array[2][3]

この配列の最初の要素へのポインターは次のようになります。

int (*array)[3]

メモリのブロックを指すことができます:

int (*array)[3] = malloc(sizeof(int)*5*3);


それがどのように索引付けされているかに注意してください。

  • array[x]に展開される*(array+x)ため、「前方に 3 つの int の x 配列」となります。
  • array[x][y]に展開される*( *(array+x) + y)ため、「y ints forward」になります。

ここにはポインタの即時配列はなく、メモリの 1 つの連続したブロックのみが含まれます。

配列の配列 (2D 配列int** ptrとは異なり、一連の行ごとの malloc を使用して行われることが多い) がある場合、次のようになります。

  • ptr[x]に展開される*(array+x)ため、「x ポインターが前方に」
  • ptr[x][y]*( *(array+x) + y)= "y ints forward"に展開されます。

違いに注意してください。どちらも [x][y] でインデックス付けされますが、メモリ内では異なる方法で表現され、インデックス付けは別の方法で行われます。

于 2012-06-08T19:10:45.650 に答える
3

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 配列と同じように機能します。 intcolsrowscolsarrayPtr[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();
      }
    }
  }
}
于 2012-06-08T19:24:51.830 に答える
0

「[]演算子は何をするのか」という質問に注意を向け直します。

[]演算子を使用して配列内の要素にアクセスする場合は、配列のジオメトリ情報が提供されていない限り、要素のサイズに基づいてのみオフセットを実行できることを理解する必要があります。

mallocには、ディメンション情報、callocのプロビジョニングがありません-明示的に1D。一方、宣言された配列(arr [3] [4])は、コンパイラーに次元を明示的に指定します。

したがって、動的に割り当てられたマルチD配列にarr [i] [j]の方法でアクセスするには、実際には、ターゲットの次元サイズの一連の1D配列を割り当てます。そのためにはループする必要があります。

mallocは、ヒープメモリへのプレーンポインタを返します。ジオメトリやデータ型に関する情報は返しません。したがって、[][]は機能しません。手動でオフセットする必要があります。

したがって、[]-インデックス作成が優先されるか、一括割り当てであるかは、あなた次第です。

于 2012-06-08T22:04:34.787 に答える
0

malloc()ポインターの配列を配列に割り当てる必要があることを知りません。要求されたサイズのメモリのチャンクを返すだけです。確かにこの方法で割り当てを行うことができますが、ポインターとして使用される最初の「行」(または最後、または行の代わりに列でさえも) を初期化する必要があります。それらは、そのチャンク内の適切な領域を指しています。

次のようにする方が効率的です。

int *arrayPtr = malloc(sizeof(int)*rows*cols);

その欠点は、使用するたびに適切なインデックスを計算する必要があることですが、それを行うための単純なヘルパー関数を作成できます。を使用して要素を参照する「便利さ」はありませんが、[]たとえばelement(arrayPtr, x, y).

于 2012-06-08T18:16:56.197 に答える
0

int **arrayPtr;は 2D 配列を指していません。へのポインターの配列を指しますint。2D 配列を作成する場合は、次を使用します。

int (*arrayPtr)[cols] = calloc(rows, sizeof *arrayPtr);
于 2012-06-08T23:09:07.763 に答える