[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次元配列を活用し、より効率的なプログラミングを目指してみてください。
 
![[C++] 配列の要素数を動的に変更する方法](https://af-e.net/wp-content/uploads/2024/10/thumbnail-47463.png)
![[C++] 配列の要素数を定数として扱う方法(constexprの活用)](https://af-e.net/wp-content/uploads/2024/10/thumbnail-47462.png)
![[C++] 配列の要素数を指定せず、後で要素数を決める方法](https://af-e.net/wp-content/uploads/2024/10/thumbnail-47460.png)
![[C++] 配列に定義できる最大要素数はいくらまで?](https://af-e.net/wp-content/uploads/2024/10/thumbnail-47458.png)
![[C++] 要素数0の配列を作成する方法 – std::vectorの応用](https://af-e.net/wp-content/uploads/2024/10/thumbnail-47456.png)
![[C++] 配列の要素数を取得する方法](https://af-e.net/wp-content/uploads/2024/10/thumbnail-47455.png)
![[C++] 二次元配列の使い方をマスターする](https://af-e.net/wp-content/uploads/2024/10/thumbnail-47454.png)
![[C++] 動的配列と静的配列の違いについて解説](https://af-e.net/wp-content/uploads/2024/10/thumbnail-47453.png)
![[C++] 動的に作成した配列を初期化する方法](https://af-e.net/wp-content/uploads/2024/10/thumbnail-47452.png)
![[C++] 配列を動的に生成して可変長配列を実装する方法](https://af-e.net/wp-content/uploads/2024/10/thumbnail-47451.png)
![[C++] 配列に様々な方法で値を代入する方法](https://af-e.net/wp-content/uploads/2024/10/thumbnail-47450.png)
![[C++] 配列の宣言と初期化について解説](https://af-e.net/wp-content/uploads/2024/10/thumbnail-47449.png)