[C++] 2次元配列を動的に生成する方法をわかりやすく解説
C++で2次元配列を動的に生成するには、ポインタを使用してメモリを動的に確保します。
まず、行数分のポインタ配列を確保し、各行に対して列数分のメモリを動的に割り当てます。
これにより、柔軟なサイズの2次元配列を作成できます。
メモリの解放も忘れずに行う必要があります。
動的に2次元配列を生成する基本的な方法
C++では、動的に2次元配列を生成するために、ポインタを使用します。
以下のサンプルコードでは、ユーザーから行数と列数を入力してもらい、そのサイズに基づいて2次元配列を動的に生成します。
#include <iostream>
int main() {
int rows, cols;
// 行数と列数を入力
std::cout << "行数を入力してください: ";
std::cin >> rows;
std::cout << "列数を入力してください: ";
std::cin >> cols;
// 2次元配列の動的生成
int** array = new int*[rows]; // 行のポインタ配列を生成
for (int i = 0; i < rows; i++) {
array[i] = new int[cols]; // 各行に列の配列を生成
}
// 配列に値を代入
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
array[i][j] = i * cols + j; // 値を設定
}
}
// 配列の内容を表示
std::cout << "2次元配列の内容:\n";
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
std::cout << array[i][j] << " "; // 値を表示
}
std::cout << std::endl; // 改行
}
// メモリの解放
for (int i = 0; i < rows; i++) {
delete[] array[i]; // 各行のメモリを解放
}
delete[] array; // 行のポインタ配列を解放
return 0;
}
行数を入力してください: 2
列数を入力してください: 3
2次元配列の内容:
0 1 2
3 4 5
このコードでは、まず行数と列数をユーザーから入力してもらい、そのサイズに基づいて2次元配列を動的に生成しています。
各要素には、行と列のインデックスを使って値を設定し、最後に配列の内容を表示しています。
メモリの解放も忘れずに行っています。
メモリの解放方法
動的に生成した2次元配列は、使用後に必ずメモリを解放する必要があります。
メモリを解放しないと、メモリリークが発生し、プログラムのパフォーマンスが低下する原因となります。
以下に、メモリの解放方法について詳しく説明します。
メモリ解放の基本
- 各行のメモリを解放: 2次元配列の各行に対して、
delete[]
を使用してメモリを解放します。 - 行のポインタ配列を解放: 最後に、行のポインタ配列自体も
delete[]
を使用して解放します。
以下のサンプルコードでは、動的に生成した2次元配列のメモリを解放する方法を示します。
#include <iostream>
int main() {
int rows = 2;
int cols = 3;
// 2次元配列の動的生成
int** array = new int*[rows]; // 行のポインタ配列を生成
for (int i = 0; i < rows; i++) {
array[i] = new int[cols]; // 各行に列の配列を生成
}
// 配列に値を代入
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
array[i][j] = i * cols + j; // 値を設定
}
}
// メモリの解放
for (int i = 0; i < rows; i++) {
delete[] array[i]; // 各行のメモリを解放
}
delete[] array; // 行のポインタ配列を解放
return 0;
}
出力結果はありませんが、このコードでは、2次元配列を生成した後、各行のメモリを解放し、最後に行のポインタ配列を解放しています。
これにより、メモリリークを防ぎ、プログラムの健全性を保つことができます。
注意点
- メモリを解放する際は、必ず
delete[]
を使用してください。
delete
を使用すると、未定義の動作を引き起こす可能性があります。
- 解放したメモリにアクセスしないように注意してください。
解放後にポインタを使用すると、プログラムがクラッシュする原因となります。
応用:動的2次元配列のサイズ変更
動的に生成した2次元配列のサイズを変更することは、プログラムの柔軟性を高めるために重要です。
C++では、サイズ変更を行うために新しい配列を作成し、既存のデータをコピーする方法が一般的です。
以下に、サイズ変更の手順とサンプルコードを示します。
サイズ変更の手順
- 新しい配列を生成: 新しい行数と列数に基づいて新しい2次元配列を動的に生成します。
- データのコピー: 既存の配列から新しい配列にデータをコピーします。
- 古い配列のメモリを解放: 古い配列のメモリを解放します。
- 新しい配列を使用: 新しい配列を使用してプログラムを続行します。
以下のサンプルコードでは、2次元配列のサイズを変更する方法を示します。
#include <iostream>
int main() {
int rows = 2;
int cols = 3;
// 初期の2次元配列の動的生成
int** array = new int*[rows];
for (int i = 0; i < rows; i++) {
array[i] = new int[cols];
}
// 配列に値を代入
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
array[i][j] = i * cols + j;
}
}
// サイズ変更のための新しい配列を生成
int newRows = 3;
int newCols = 4;
int** newArray = new int*[newRows];
for (int i = 0; i < newRows; i++) {
newArray[i] = new int[newCols];
}
// データのコピー
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
newArray[i][j] = array[i][j]; // 既存のデータをコピー
}
}
// 古い配列のメモリを解放
for (int i = 0; i < rows; i++) {
delete[] array[i];
}
delete[] array;
// 新しい配列に値を設定
for (int i = 0; i < newRows; i++) {
for (int j = cols; j < newCols; j++) {
newArray[i][j] = i * newCols + j; // 新しい要素に値を設定
}
}
// 新しい配列の内容を表示
std::cout << "新しい2次元配列の内容:\n";
for (int i = 0; i < newRows; i++) {
for (int j = 0; j < newCols; j++) {
std::cout << newArray[i][j] << " ";
}
std::cout << std::endl;
}
// 新しい配列のメモリを解放
for (int i = 0; i < newRows; i++) {
delete[] newArray[i];
}
delete[] newArray;
return 0;
}
新しい2次元配列の内容:
0 1 2 6
3 4 5 7
8 9 10 11
このコードでは、最初に2次元配列を生成し、次に新しいサイズの配列を生成して既存のデータをコピーしています。
古い配列のメモリを解放した後、新しい配列に新しい要素を設定し、最終的に新しい配列の内容を表示しています。
これにより、動的に2次元配列のサイズを変更することができます。
エラー処理と例外対応
動的に2次元配列を生成する際には、メモリの割り当てに失敗する可能性があります。
特に、大きな配列を生成しようとした場合や、システムのメモリが不足している場合にエラーが発生することがあります。
C++では、例外処理を使用してこれらのエラーに対処することができます。
以下に、エラー処理と例外対応の方法を示します。
例外処理の基本
new
演算子の使用:new
演算子は、メモリの割り当てに失敗した場合にstd::bad_alloc
例外をスローします。try
とcatch
ブロック:try
ブロック内でメモリの割り当てを行い、catch
ブロックで例外をキャッチして適切なエラーメッセージを表示します。
以下のサンプルコードでは、動的に2次元配列を生成する際のエラー処理を示します。
#include <iostream>
#include <new> // std::bad_allocを使用するために必要
int main() {
int rows = 2;
int cols = 3;
try {
// 2次元配列の動的生成
int** array = new int*[rows]; // 行のポインタ配列を生成
for (int i = 0; i < rows; i++) {
array[i] = new int[cols]; // 各行に列の配列を生成
}
// 配列に値を代入
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
array[i][j] = i * cols + j; // 値を設定
}
}
// 配列の内容を表示
std::cout << "2次元配列の内容:\n";
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
std::cout << array[i][j] << " "; // 値を表示
}
std::cout << std::endl; // 改行
}
// メモリの解放
for (int i = 0; i < rows; i++) {
delete[] array[i]; // 各行のメモリを解放
}
delete[] array; // 行のポインタ配列を解放
} catch (const std::bad_alloc& e) {
// メモリ割り当てに失敗した場合の処理
std::cerr << "メモリの割り当てに失敗しました: " << e.what() << std::endl;
}
return 0;
}
出力結果(メモリ割り当てに成功した場合):
2次元配列の内容:
0 1 2
3 4 5
このコードでは、try
ブロック内で2次元配列を動的に生成し、catch
ブロックでstd::bad_alloc
例外をキャッチしています。
メモリの割り当てに失敗した場合には、エラーメッセージを表示することで、プログラムが適切にエラーに対処できるようにしています。
これにより、プログラムの安定性が向上し、予期しないクラッシュを防ぐことができます。
実践例:動的2次元配列の活用
動的2次元配列は、さまざまなアプリケーションで活用されます。
特に、行列計算、画像処理、ゲームのマップデータなど、データを行と列で管理する必要がある場合に便利です。
ここでは、動的2次元配列を使用して簡単な行列の加算を行う実践例を示します。
行列加算の手順
- 行列のサイズを入力: ユーザーから行列の行数と列数を入力してもらいます。
- 2つの行列を動的に生成: 入力されたサイズに基づいて、2つの行列を動的に生成します。
- 行列の要素を入力: ユーザーから各行列の要素を入力してもらいます。
- 行列の加算: 2つの行列を加算し、結果を新しい行列に格納します。
- 結果を表示: 加算結果の行列を表示します。
- メモリの解放: 使用したメモリを解放します。
以下のサンプルコードでは、行列の加算を実装しています。
#include <iostream>
int main() {
int rows, cols;
// 行数と列数を入力
std::cout << "行数を入力してください: ";
std::cin >> rows;
std::cout << "列数を入力してください: ";
std::cin >> cols;
// 2つの行列の動的生成
int** matrixA = new int*[rows];
int** matrixB = new int*[rows];
int** resultMatrix = new int*[rows];
for (int i = 0; i < rows; i++) {
matrixA[i] = new int[cols];
matrixB[i] = new int[cols];
resultMatrix[i] = new int[cols];
}
// 行列Aの要素を入力
std::cout << "行列Aの要素を入力してください:\n";
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
std::cout << "A[" << i << "][" << j << "] = ";
std::cin >> matrixA[i][j];
}
}
// 行列Bの要素を入力
std::cout << "行列Bの要素を入力してください:\n";
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
std::cout << "B[" << i << "][" << j << "] = ";
std::cin >> matrixB[i][j];
}
}
// 行列の加算
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
resultMatrix[i][j] = matrixA[i][j] + matrixB[i][j]; // 加算
}
}
// 結果を表示
std::cout << "行列の加算結果:\n";
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
std::cout << resultMatrix[i][j] << " "; // 結果を表示
}
std::cout << std::endl; // 改行
}
// メモリの解放
for (int i = 0; i < rows; i++) {
delete[] matrixA[i];
delete[] matrixB[i];
delete[] resultMatrix[i];
}
delete[] matrixA;
delete[] matrixB;
delete[] resultMatrix;
return 0;
}
行数を入力してください: 2
列数を入力してください: 2
行列Aの要素を入力してください:
A[0][0] = 1
A[0][1] = 2
A[1][0] = 3
A[1][1] = 4
行列Bの要素を入力してください:
B[0][0] = 5
B[0][1] = 6
B[1][0] = 7
B[1][1] = 8
行列の加算結果:
6 8
10 12
このコードでは、ユーザーから行列のサイズと要素を入力してもらい、2つの行列を加算して結果を表示しています。
動的2次元配列を使用することで、行列のサイズを柔軟に変更でき、さまざまなサイズの行列に対応することができます。
このように、動的2次元配列は実践的なアプリケーションで非常に役立ちます。
まとめ
この記事では、C++における動的2次元配列の生成方法やメモリの解放、サイズ変更、エラー処理、実践的な活用例について詳しく解説しました。
動的2次元配列は、柔軟なデータ管理を可能にし、さまざまなアプリケーションでの利用が期待されます。
今後は、実際のプロジェクトで動的2次元配列を活用し、より効率的なプログラミングを目指してみてください。