web-dev-qa-db-ja.com

行の長さが異なる多次元配列の割り当てにmallocを使用する

次のCコードがあります。

int *a;
size_t size = 2000*sizeof(int);
a = (int *) malloc(size);

正常に動作します。しかし、私が次のものを持っている場合:

char **b = malloc(2000*sizeof *b);

ここで、bのすべての要素の長さは異なります。

bで行ったのと同じことをaでできるのはどうしてですか。つまり、次のコードは正しいでしょうか?

char *c;
size_t size = 2000*sizeof(char *);
c = (char *) malloc(size);
65
asel

まず、char **c = malloc( N * sizeof( char* ))のようなポインターの配列を割り当てる必要があります。次に、おそらくループ内で、mallocへの個別の呼び出しで各行を割り当てます。


/* N is the number of rows  */
/* note: c is char** */
if (( c = malloc( N*sizeof( char* ))) == NULL )
{ /* error */ }

for ( i = 0; i < N; i++ )
{
  /* x_i here is the size of given row, no need to
   * multiply by sizeof( char ), it's always 1
   */
  if (( c[i] = malloc( x_i )) == NULL )
  { /* error */ }

  /* probably init the row here */
}

/* access matrix elements: c[i] give you a pointer
 * to the row array, c[i][j] indexes an element
 */
c[i][j] = 'a';

要素の総数(例:N*M)がわかっている場合は、1回の割り当てでこれを実行できます。

76

タイプTのNxM配列を動的に割り当てる一般的な形式は次のとおりです。

T **a = malloc(sizeof *a * N);
if (a)
{
  for (i = 0; i < N; i++)
  {
    a[i] = malloc(sizeof *a[i] * M);
  }
}

配列の各要素の長さが異なる場合、Mをその要素の適切な長さに置き換えます。例えば

T **a = malloc(sizeof *a * N);
if (a)
{
  for (i = 0; i < N; i++)
  {
    a[i] = malloc(sizeof *a[i] * length_for_this_element);
  }
}
48
John Bode

char a[10][20]に相当するメモリ割り当ては次のようになります。

char **a;

a=(char **) malloc(10*sizeof(char *));

for(i=0;i<10;i++)
    a[i]=(char *) malloc(20*sizeof(char));

これが理解しやすいように願っています。

28
Ramesh

もう1つのアプローチは、行へのポインターのヘッダーブロックと、実際のデータを行に格納するための本体ブロックで構成される1つの連続したメモリチャンクを割り当てることです。次に、本体のメモリのアドレスを行ごとにヘッダーのポインタに割り当てて、メモリをマークアップします。次のようになります。

int** 2dAlloc(int rows, int* columns) {    
    int header = rows * sizeof(int*);

    int body = 0;
    for(int i=0; i<rows; body+=columnSizes[i++]) {  
    }
    body*=sizeof(int);

    int** rowptr = (int**)malloc(header + body);

    int* buf  = (int*)(rowptr + rows);
    rowptr[0] = buf;
    int k;
    for(k = 1; k < rows; ++k) {
        rowptr[k] = rowptr[k-1] + columns[k-1];
    }
    return rowptr;
}

int main() {
    // specifying column amount on per-row basis
    int columns[] = {1,2,3};
    int rows = sizeof(columns)/sizeof(int);
    int** matrix = 2dAlloc(rows, &columns);

    // using allocated array
    for(int i = 0; i<rows; ++i) {
        for(int j = 0; j<columns[i]; ++j) {
            cout<<matrix[i][j]<<", ";
        }   
            cout<<endl;
    }

    // now it is time to get rid of allocated 
    // memory in only one call to "free"
    free matrix;
}

このアプローチの利点は、メモリをエレガントに解放し、配列のような表記法を使用して結果の2D配列の要素にアクセスできることです。

10
Dmitry Aleks

Bのすべての要素の長さが異なる場合、次のようにする必要があります。

int totalLength = 0;
for_every_element_in_b {
    totalLength += length_of_this_b_in_bytes;
}
return (char **)malloc(totalLength);
3
plinth

C 2-d配列は配列の配列であるため、2段階のアプローチが最適だと思います。最初の手順は、単一の配列を割り当てることです。次に、ループを実行して、列ごとに配列を割り当てます。 この記事 は詳細を示しています。

2
zdav

2次元配列の動的メモリ割り当て

int **a,i;

// for any number of rows & columns this will work
a = (int **)malloc(rows*sizeof(int *));
for(i=0;i<rows;i++)
    *(a+i) = (int *)malloc(cols*sizeof(int));
1
Sridhar T

mallocは特定の境界に割り当てないため、バイト境界に割り当てると仮定する必要があります。

返されたポインターは、他の型に変換された場合は使用できません。そのポインターにアクセスすると、CPUによるメモリアクセス違反が発生し、アプリケーションが直ちにシャットダウンされるためです。

0