C++で二次元配列を動的生成する3つの方法

C++で二次元配列を動的生成するには?ということで、思いついた3つの方法

①newする
動的生成といえばnew。C言語ならmallocとかcallocにあたります
以下はint型の二次元配列をnewして使ってdeleteする方法

#include<iostream>
using namespace std;

int main(){
	/* new */
	// int*の配列を動的生成
	int **arr = new int*[20];
	// 配列の各要素でintの配列を動的生成
	for( int i=0; i<20; i++ ){
		arr[i] = new int[10];
	}

	// 実際に配列を使ってなんやかんや
	arr[19][9] = 12345;
	cout << arr[19][9] << endl;

	/* delete */
	// 各要素を先にdelete
	for( int i=0; i<20; i++ ){
		delete[] arr[i];
		arr[i] = 0;	// ※(記事の最後の方で説明)
	}
	delete[] arr;
	arr = 0;	// ※

	return 0;
}

newをすると必ずdeleteが必要になり、し忘れるとメモリリークを起こします
そんな危険性を含んでいる①、正直おすすめの方法ではありません


STLvectorを使う
みんな大好きSTLC++の標準ライブラリのことです
これを使って二次元配列を動的生成してみましょう

#include<iostream>
#include<vector>	// vectorを使うにはこれが必要
using namespace std;

int main(){
	// resize関数を使って動的にサイズを変えれる
	vector< vector<int> > arr;
	arr.resize(20);		// ()内の数字が要素数になる
	for( int i=0; i<20; i++ ){
		arr[i].resize(10);
	}

	arr[19][9] = 12345;
	cout << arr[19][9] << endl;

	// deleteのような処理はデストラクタ内で行なってくれるので不要

	return 0;
}

①より簡単で危険性も減ります。おすすめ


③一次元配列を二次元配列のように使う
最後はこれです。とりあえずサンプルコード

#include<iostream>
using namespace std;

int main(){
	int *arr;
	// [20][10]の二次元配列を生成
	arr = new int[20*10];

	// arr[19][9]に代入
	arr[9*20+19] = 12345;
	// arr[19][9]の値を表示
	cout << arr[9*20+19] << endl;

	delete[] arr;
	arr = 0;

	return 0;
}

幅w,高さhの二次元配列を作りたいとき、w*hの一次元配列を生成します
そして要素[x][y]へのアクセスの際に[y*w+x]とすることで、一次元配列を二次元配列のように扱えます
vectorは使いたくないという人にはこの方法をおすすめします。①よりは単純になります


※について。余談というか補足というか
deleteした後のポインタには0を代入しておくことが望ましいです
というのも、deleteした後のポインタにはnewの時に代入されたアドレスがそのまま格納されているからです
そして、変数aをdeleteした後にnewした変数bのアドレスは変数aと同じであることがあるからです
例えば、下記のようなコード

#include<iostream>
using namespace std;

int main(){
	int *a = new int();
	cout << a << endl;	// 0x381ee0(自分がテストした時はこのアドレスだった)
	delete a;
	cout << a << endl;	// 0x381ee0。delete前と同じ

	int *b = new int();
	cout << b << endl;	// 0x381ee0。aと同じ
	*b = 0;
	cout << *b << endl;	// 「0」と表示される
	*a = 100;			// aをdeleteしたことを忘れて、代入すると…(これが怖いから※1の処理をしてる)
	cout << *b << endl;	// 「100」と表示される!
	delete b;

	return 0;
}

このようなことが発生し、思わぬ所でデータをぶっ壊したりします。やべぇ
そんなことがないように、使い終わったポインタには0を入れることをオススメします