読者です 読者をやめる 読者になる 読者になる

FLYING

〈全日本・紀文豆乳飲料シリーズ「麦芽コーヒー」の500ミリリットルパックを扱う小売店が少ないことに遺憾の意を表明する会〉活動記録

C言語で2次元配列を動的に割り当てる4つの方法

c/c++

2次元配列を動的割り当てしたいそんなとき,C言語ならキモくなるかも。

検索エンジンから来る人がそれなりに居るようなので,解説画像を追加しました(2014/12/05)。

各行のデータを保持する配列と各行へのポインタを保持する配列に分けて確保

おそらく最も基本的なやり方。

int **matrix;
int i, j, n, m;
n = 100, m = 100;

matrix = malloc(sizeof(int *) * n);
for (i=0;i<n;i++) {
	matrix[i] = malloc(sizeof(int) * m);
}

for (i=0;i<n;i++) {
	for (j=0;j<m;j++) {
		matrix[i][j] = i * m + j;
		printf("%d\n", matrix[i][j]);
	}
}

for (i=0;i<n;i++) {
	free(matrix[i]);
}
free(matrix);

確保時と解放時にループが必要でめんどくさい。メモリ領域が連続で確保されないのがデメリットだが,各行の要素数が違うマジキチなデータ構造を実現したいならこれしかない。

f:id:tondol:20141205155142p:plain

各行のデータを保持する配列を連続した領域で確保

1個目の方法の改良版。

int **matrix, *base_matrix;
int i, j, n, m;
n = 100, m = 100;

matrix = malloc(sizeof(int *) * n);
base_matrix = malloc(sizeof(int) * n * m);
for (i=0;i<n;i++) {
	matrix[i] = base_matrix + i * m;
}

for (i=0;i<n;i++) {
	for (j=0;j<m;j++) {
		matrix[i][j] = i * m + j;
		printf("%d\n", matrix[i][j]);
	}
}

free(base_matrix);
free(matrix);

連続した領域を確保できるので,2重ループを用いた配列へのアクセスを高速化できるかも。1個目の方法に比べて解放が若干楽になるのもメリット。

f:id:tondol:20141205155152p:plain

1次元配列として確保

実用上はこれを使うことが多そう。

int *matrix;
int i, j, n, m;
n = 100, m = 100;

matrix = malloc(sizeof(int) * n * m);

for (i=0;i<n;i++) {
	for (j=0;j<m;j++) {
		matrix[i * m + j] = i * m + j;
		printf("%d\n", matrix[i * m + j]);
	}
}

free(matrix);

ポインタの配列を確保しないで済むので,1個目や2個目の方法に比べて必要なメモリ領域が少ない。また,1次元配列なのでポインタについてごちゃごちゃ悩まずに利用できる。

f:id:tondol:20141205155203p:plain

配列へのポインタを利用

低次元側の要素数を固定していいならばこんな方法もある。

int (*matrix)[100];
int i, j, n, m;
n = 100, m = 100;

matrix = malloc(sizeof(int) * n * m);

for (i=0;i<n;i++) {
	for (j=0;j<m;j++) {
		matrix[i][j] = i * m + j;
		printf("%d\n", matrix[i][j]);
	}
}

free(matrix);

宣言が若干キモい以外は通常の2次元配列とほぼ同様に扱える。個人的に,文字列の配列が欲しい場合はこの方法を使うことが多い。

f:id:tondol:20141205155212p:plain