次の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);
まず、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回の割り当てでこれを実行できます。
タイプ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);
}
}
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));
これが理解しやすいように願っています。
もう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配列の要素にアクセスできることです。
Bのすべての要素の長さが異なる場合、次のようにする必要があります。
int totalLength = 0;
for_every_element_in_b {
totalLength += length_of_this_b_in_bytes;
}
return (char **)malloc(totalLength);
C 2-d配列は配列の配列であるため、2段階のアプローチが最適だと思います。最初の手順は、単一の配列を割り当てることです。次に、ループを実行して、列ごとに配列を割り当てます。 この記事 は詳細を示しています。
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));
mallocは特定の境界に割り当てないため、バイト境界に割り当てると仮定する必要があります。
返されたポインターは、他の型に変換された場合は使用できません。そのポインターにアクセスすると、CPUによるメモリアクセス違反が発生し、アプリケーションが直ちにシャットダウンされるためです。