配列

[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次元配列は、使用後に必ずメモリを解放する必要があります。

メモリを解放しないと、メモリリークが発生し、プログラムのパフォーマンスが低下する原因となります。

以下に、メモリの解放方法について詳しく説明します。

メモリ解放の基本

  1. 各行のメモリを解放: 2次元配列の各行に対して、delete[]を使用してメモリを解放します。
  2. 行のポインタ配列を解放: 最後に、行のポインタ配列自体も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++では、サイズ変更を行うために新しい配列を作成し、既存のデータをコピーする方法が一般的です。

以下に、サイズ変更の手順とサンプルコードを示します。

サイズ変更の手順

  1. 新しい配列を生成: 新しい行数と列数に基づいて新しい2次元配列を動的に生成します。
  2. データのコピー: 既存の配列から新しい配列にデータをコピーします。
  3. 古い配列のメモリを解放: 古い配列のメモリを解放します。
  4. 新しい配列を使用: 新しい配列を使用してプログラムを続行します。

以下のサンプルコードでは、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++では、例外処理を使用してこれらのエラーに対処することができます。

以下に、エラー処理と例外対応の方法を示します。

例外処理の基本

  1. new演算子の使用: new演算子は、メモリの割り当てに失敗した場合にstd::bad_alloc例外をスローします。
  2. trycatchブロック: 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次元配列を使用して簡単な行列の加算を行う実践例を示します。

行列加算の手順

  1. 行列のサイズを入力: ユーザーから行列の行数と列数を入力してもらいます。
  2. 2つの行列を動的に生成: 入力されたサイズに基づいて、2つの行列を動的に生成します。
  3. 行列の要素を入力: ユーザーから各行列の要素を入力してもらいます。
  4. 行列の加算: 2つの行列を加算し、結果を新しい行列に格納します。
  5. 結果を表示: 加算結果の行列を表示します。
  6. メモリの解放: 使用したメモリを解放します。

以下のサンプルコードでは、行列の加算を実装しています。

#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次元配列を活用し、より効率的なプログラミングを目指してみてください。

関連記事

Back to top button