5

これらの 2 つのケースでは、配列へのアクセスまたはメモリ割り当てにどのような影響がありますか。

1.

    int **arr;
    arr = malloc( sizeof(int) * row * column );

2.

    int **arr;
    arr = malloc( sizeof(*arr) * row);
    for(i=0; i<row; i++)
        arr[i] = malloc( sizeof( **arr) * column));
4

1 に答える 1

6
  • まず、「影響」は、最初の方法が壊れていることです。int **ポインターでは機能しません。

    最初の方法で 2D 配列を 1 回で割り当てるには、実際には十分なサイズの 1D 配列を割り当てる必要があります。

    int *arr = malloc( row * column * sizeof *arr );
    // Note: `int *`, not `int **`
    

    arr[i][j]たとえば、する必要があるのではなく、手動でインデックスを再計算してアクセスを実行しますarr[i * column + j]

    割り当てられたポインターを格納してからint **arr配列にアクセスしようとすると、arr[i][j]単にクラッシュするだけです。

  • 次に、2 番目の方法で問題ありません。malloc2 番目の方法では、複数の独立した呼び出しによって第 2 レベルのメモリを割り当てる必要がないというだけです。2 番目のレベルのメモリ全体を 1 回で割り当てることができます

    int **arr = malloc( row  * sizeof *arr );
    int *arr_data = malloc( row * column * sizeof *arr_data );
    

    次に、事前に割り当てられた第2レベルのメモリを行間で分配します

    for (i = 0; i < row; i++)
      arr[i] = arr_data + i * column;
    

    (もちろん、必要に応じて、行を個別に割り当てることもできます。それも機能します。以下でコメントするように、最初のアプローチと 2 番目のアプローチの類似性をよりよく説明するために、それらを一度に割り当てたかったのです。)

さて、これら 2 つのメソッドを見ると、どちらも本質的に同じことを行うことが簡単にわかります。arr + i * column唯一の違いは、最初の方法では、毎回計算することでその場で行の先頭を見つけることです(arr[i * column + j]は と同等であることに注意してください(arr + i * column)[j])。2 番目の方法では、同じ数式を使用してすべての行の開始点を事前に計算し、arr_data + i * column後で使用するために別の「行インデックス」配列に格納しarrます。

したがって、基本的には、メモリ使用量 (最初の方法では必要なメモリが少なくて済みます) と速度 (2 番目の方法の方が高速である可能性がありますが、必ずしもそうではありません) の間のトレードオフになります。同時に、2 番目の方法は 2D 配列アクセスの「自然な」構文をサポートしますarr[i][j]が、最初の方法では、インデックスの再計算を伴うより複雑な 1D アクセス構文を使用する必要があります。

于 2013-07-04T19:48:32.193 に答える