配列

[C++] 2次元配列をポインタで使う方法をわかりやすく解説

C++で2次元配列をポインタで扱う方法は、配列のメモリ構造を理解することが重要です。

2次元配列は実際には連続したメモリ領域に格納されており、ポインタを使ってアクセスできます。

例えば、int arr[3][4];の場合、arrは最初の行の先頭アドレスを指します。

ポインタを使う場合、int (*p)[4] = arr;のように行ポインタを定義し、p[i][j]で要素にアクセスします。

また、動的に確保する場合はnewを使い、int**型のポインタを用いる方法もあります。

2次元配列とポインタの基本

C++における2次元配列は、配列の配列として表現されます。

ポインタを使うことで、メモリの効率的な管理や動的な配列の操作が可能になります。

ここでは、2次元配列とポインタの基本的な概念を解説します。

2次元配列の定義

2次元配列は、行と列を持つ配列です。

以下のように定義できます。

#include <iostream>
using namespace std;
int main() {
    // 3行2列の静的2次元配列を定義
    int array[3][2] = {
        {1, 2},
        {3, 4},
        {5, 6}
    };
    // 配列の要素を出力
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 2; j++) {
            cout << array[i][j] << " "; // 要素を出力
        }
        cout << endl; // 行の区切り
    }
    return 0;
}
1 2 
3 4 
5 6

ポインタを使った2次元配列の扱い

ポインタを使うことで、2次元配列の要素にアクセスすることができます。

以下のようにポインタを使った例を示します。

#include <iostream>
using namespace std;
int main() {
    // 3行2列の静的2次元配列を定義
    int array[3][2] = {
        {1, 2},
        {3, 4},
        {5, 6}
    };
    // ポインタを使って配列の要素にアクセス
    int (*ptr)[2] = array; // 2次元配列のポインタ
    // ポインタを使って要素を出力
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 2; j++) {
            cout << ptr[i][j] << " "; // 要素を出力
        }
        cout << endl; // 行の区切り
    }
    return 0;
}
1 2 
3 4 
5 6

2次元配列のメモリ構造

2次元配列はメモリ上で連続して配置されます。

各行は連続したメモリ領域に格納され、ポインタを使ってそのアドレスを操作することができます。

これにより、動的なメモリ管理が可能になります。

2次元配列とポインタを組み合わせることで、C++におけるメモリ管理が効率的に行えます。

ポインタを使うことで、配列の要素に直接アクセスでき、柔軟なプログラミングが可能になります。

静的配列をポインタで扱う方法

静的配列は、コンパイル時にサイズが決定される配列です。

ポインタを使用することで、静的配列の要素にアクセスしたり、操作したりすることができます。

ここでは、静的配列をポインタで扱う方法について解説します。

静的配列の定義とポインタの初期化

まず、静的配列を定義し、そのポインタを初期化する方法を見てみましょう。

#include <iostream>
using namespace std;
int main() {
    // 5要素の静的配列を定義
    int array[5] = {10, 20, 30, 40, 50};
    // 配列の先頭アドレスをポインタに代入
    int* ptr = array; // arrayは配列の先頭アドレスを指すポインタ
    // ポインタを使って要素を出力
    for (int i = 0; i < 5; i++) {
        cout << *(ptr + i) << " "; // ポインタを使って要素にアクセス
    }
    cout << endl; // 改行
    return 0;
}
10 20 30 40 50

ポインタを使った要素の変更

ポインタを使って静的配列の要素を変更することもできます。

以下の例では、ポインタを使って配列の要素を変更しています。

#include <iostream>
using namespace std;
int main() {
    // 5要素の静的配列を定義
    int array[5] = {10, 20, 30, 40, 50};
    // 配列の先頭アドレスをポインタに代入
    int* ptr = array; // arrayは配列の先頭アドレスを指すポインタ
    // ポインタを使って要素を変更
    *(ptr + 2) = 100; // 3番目の要素を100に変更
    // 変更後の要素を出力
    for (int i = 0; i < 5; i++) {
        cout << *(ptr + i) << " "; // ポインタを使って要素にアクセス
    }
    cout << endl; // 改行
    return 0;
}
10 20 100 40 50

ポインタと配列の関係

ポインタと配列は密接に関連しています。

配列名はその配列の先頭要素のアドレスを指すため、ポインタを使って配列の要素にアクセスすることができます。

この特性を利用することで、配列の操作がより柔軟になります。

静的配列をポインタで扱うことで、配列の要素に直接アクセスしたり、変更したりすることが可能です。

ポインタを使うことで、配列の操作が効率的になり、プログラムの柔軟性が向上します。

動的に確保した2次元配列の扱い方

C++では、new演算子を使用して動的にメモリを確保することができます。

これにより、プログラムの実行時に必要なサイズの2次元配列を作成することが可能になります。

ここでは、動的に確保した2次元配列の扱い方について解説します。

動的2次元配列の作成

まず、動的に2次元配列を作成する方法を見てみましょう。

以下の例では、newを使って2次元配列を動的に確保しています。

#include <iostream>
using namespace std;
int main() {
    int rows = 3; // 行数
    int cols = 2; // 列数
    // 動的に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 + 1) * (j + 1); // 値を代入
        }
    }
    // 配列の要素を出力
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            cout << array[i][j] << " "; // 要素を出力
        }
        cout << endl; // 行の区切り
    }
    // メモリの解放
    for (int i = 0; i < rows; i++) {
        delete[] array[i]; // 各行のメモリを解放
    }
    delete[] array; // 行のポインタのメモリを解放
    return 0;
}
1 2 
2 4 
3 6

動的2次元配列のメモリ管理

動的に確保した2次元配列は、使用後に必ずメモリを解放する必要があります。

delete演算子を使用して、確保したメモリを解放します。

上記の例では、各行のメモリを解放した後、行のポインタ自体のメモリも解放しています。

これにより、メモリリークを防ぐことができます。

ポインタを使った要素のアクセス

動的に確保した2次元配列の要素には、ポインタを使ってアクセスすることもできます。

以下の例では、ポインタを使って要素にアクセスし、値を変更しています。

#include <iostream>
using namespace std;
int main() {
    int rows = 3; // 行数
    int cols = 2; // 列数
    // 動的に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 + 1) * (j + 1);
        }
    }
    // ポインタを使って要素を変更
    int* ptr = &array[1][0]; // 2行目の先頭要素のポインタ
    *ptr = 99; // 変更
    // 配列の要素を出力
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            cout << array[i][j] << " "; // 要素を出力
        }
        cout << endl; // 行の区切り
    }
    // メモリの解放
    for (int i = 0; i < rows; i++) {
        delete[] array[i];
    }
    delete[] array;
    return 0;
}
1 2 
99 4 
3 6

動的に確保した2次元配列は、実行時に必要なサイズを柔軟に扱うことができ、ポインタを使って要素にアクセスすることが可能です。

メモリ管理を適切に行うことで、効率的なプログラミングが実現できます。

関数で2次元配列を扱う方法

C++では、関数を使って2次元配列を扱うことができます。

配列を引数として渡すことで、関数内で配列の要素にアクセスしたり、操作したりすることが可能です。

ここでは、関数で2次元配列を扱う方法について解説します。

静的2次元配列を関数に渡す

まず、静的に定義された2次元配列を関数に渡す方法を見てみましょう。

以下の例では、2次元配列を引数として受け取り、その要素を出力する関数を定義しています。

#include <iostream>
using namespace std;
// 2次元配列を引数に取る関数
void printArray(int array[3][2]) {
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 2; j++) {
            cout << array[i][j] << " "; // 要素を出力
        }
        cout << endl; // 行の区切り
    }
}
int main() {
    // 3行2列の静的2次元配列を定義
    int array[3][2] = {
        {1, 2},
        {3, 4},
        {5, 6}
    };
    // 関数を呼び出して配列を出力
    printArray(array);
    return 0;
}
1 2 
3 4 
5 6

動的2次元配列を関数に渡す

次に、動的に確保した2次元配列を関数に渡す方法を見てみましょう。

以下の例では、動的に確保した2次元配列を引数として受け取り、その要素を出力する関数を定義しています。

#include <iostream>
using namespace std;
// 動的2次元配列を引数に取る関数
void printDynamicArray(int** array, int rows, int cols) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            cout << array[i][j] << " "; // 要素を出力
        }
        cout << endl; // 行の区切り
    }
}
int main() {
    int rows = 3; // 行数
    int cols = 2; // 列数
    // 動的に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 + 1) * (j + 1);
        }
    }
    // 関数を呼び出して配列を出力
    printDynamicArray(array, rows, cols);
    // メモリの解放
    for (int i = 0; i < rows; i++) {
        delete[] array[i];
    }
    delete[] array;
    return 0;
}
1 2 
2 4 
3 6

2次元配列を返す関数

C++では、2次元配列を返す関数を作成することもできますが、ポインタを使って動的に確保した配列を返す必要があります。

以下の例では、動的に2次元配列を生成し、それを返す関数を定義しています。

#include <iostream>
using namespace std;
// 動的に2次元配列を生成する関数
int** createDynamicArray(int rows, int cols) {
    int** array = new int*[rows];
    for (int i = 0; i < rows; i++) {
        array[i] = new int[cols];
    }
    return array; // 配列のポインタを返す
}
int main() {
    int rows = 3; // 行数
    int cols = 2; // 列数
    // 関数を呼び出して動的2次元配列を生成
    int** array = createDynamicArray(rows, cols);
    // 配列に値を代入
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            array[i][j] = (i + 1) * (j + 1);
        }
    }
    // 配列の要素を出力
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            cout << array[i][j] << " "; // 要素を出力
        }
        cout << endl; // 行の区切り
    }
    // メモリの解放
    for (int i = 0; i < rows; i++) {
        delete[] array[i];
    }
    delete[] array;
    return 0;
}
1 2 
2 4 
3 6

関数を使って2次元配列を扱うことで、配列の要素にアクセスしたり、操作したりすることができます。

静的配列と動的配列の両方に対応した関数を定義することで、柔軟なプログラミングが可能になります。

2次元配列とポインタの応用例

2次元配列とポインタを組み合わせることで、さまざまなプログラミングのシナリオに対応できます。

ここでは、2次元配列とポインタを活用したいくつかの応用例を紹介します。

1. 行列の加算

2次元配列を使って行列の加算を行うプログラムの例です。

ポインタを使って配列の要素にアクセスし、結果を新しい配列に格納します。

#include <iostream>
using namespace std;
// 行列の加算を行う関数
void addMatrices(int** matrixA, int** matrixB, int** result, int rows, int cols) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            result[i][j] = matrixA[i][j] + matrixB[i][j]; // 要素の加算
        }
    }
}
int main() {
    int rows = 2; // 行数
    int cols = 2; // 列数
    // 動的に2次元配列を確保
    int** matrixA = new int*[rows];
    int** matrixB = new int*[rows];
    int** result = new int*[rows];
    for (int i = 0; i < rows; i++) {
        matrixA[i] = new int[cols];
        matrixB[i] = new int[cols];
        result[i] = new int[cols];
    }
    // 行列Aの値を代入
    matrixA[0][0] = 1; matrixA[0][1] = 2;
    matrixA[1][0] = 3; matrixA[1][1] = 4;
    // 行列Bの値を代入
    matrixB[0][0] = 5; matrixB[0][1] = 6;
    matrixB[1][0] = 7; matrixB[1][1] = 8;
    // 行列の加算
    addMatrices(matrixA, matrixB, result, rows, cols);
    // 結果を出力
    cout << "Result of Matrix Addition:" << endl;
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            cout << result[i][j] << " "; // 要素を出力
        }
        cout << endl; // 行の区切り
    }
    // メモリの解放
    for (int i = 0; i < rows; i++) {
        delete[] matrixA[i];
        delete[] matrixB[i];
        delete[] result[i];
    }
    delete[] matrixA;
    delete[] matrixB;
    delete[] result;
    return 0;
}
Result of Matrix Addition:
6 8 
10 12

2. 2次元配列の転置

2次元配列の転置を行うプログラムの例です。

ポインタを使って元の配列の要素を新しい配列にコピーします。

#include <iostream>
using namespace std;
// 行列の転置を行う関数
void transposeMatrix(int** matrix, int** transposed, int rows, int cols) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            transposed[j][i] = matrix[i][j]; // 転置
        }
    }
}
int main() {
    int rows = 2; // 行数
    int cols = 3; // 列数
    // 動的に2次元配列を確保
    int** matrix = new int*[rows];
    int** transposed = new int*[cols];
    for (int i = 0; i < rows; i++) {
        matrix[i] = new int[cols];
    }
    for (int j = 0; j < cols; j++) {
        transposed[j] = new int[rows];
    }
    // 行列の値を代入
    matrix[0][0] = 1; matrix[0][1] = 2; matrix[0][2] = 3;
    matrix[1][0] = 4; matrix[1][1] = 5; matrix[1][2] = 6;
    // 行列の転置
    transposeMatrix(matrix, transposed, rows, cols);
    // 転置結果を出力
    cout << "Transposed Matrix:" << endl;
    for (int j = 0; j < cols; j++) {
        for (int i = 0; i < rows; i++) {
            cout << transposed[j][i] << " "; // 要素を出力
        }
        cout << endl; // 行の区切り
    }
    // メモリの解放
    for (int i = 0; i < rows; i++) {
        delete[] matrix[i];
    }
    for (int j = 0; j < cols; j++) {
        delete[] transposed[j];
    }
    delete[] matrix;
    delete[] transposed;
    return 0;
}
Transposed Matrix:
1 4 
2 5 
3 6

3. 2次元配列の探索

2次元配列内の特定の値を探索するプログラムの例です。

ポインタを使って配列の要素にアクセスし、指定した値が存在するかどうかを確認します。

#include <iostream>
using namespace std;
// 2次元配列内の値を探索する関数
bool searchValue(int** matrix, int rows, int cols, int value) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            if (matrix[i][j] == value) {
                return true; // 値が見つかった場合
            }
        }
    }
    return false; // 値が見つからなかった場合
}
int main() {
    int rows = 2; // 行数
    int cols = 3; // 列数
    // 動的に2次元配列を確保
    int** matrix = new int*[rows];
    for (int i = 0; i < rows; i++) {
        matrix[i] = new int[cols];
    }
    // 行列の値を代入
    matrix[0][0] = 1; matrix[0][1] = 2; matrix[0][2] = 3;
    matrix[1][0] = 4; matrix[1][1] = 5; matrix[1][2] = 6;
    // 値を探索
    int valueToFind = 5;
    if (searchValue(matrix, rows, cols, valueToFind)) {
        cout << valueToFind << " は行列内に存在します。" << endl;
    } else {
        cout << valueToFind << " は行列内に存在しません。" << endl;
    }
    // メモリの解放
    for (int i = 0; i < rows; i++) {
        delete[] matrix[i];
    }
    delete[] matrix;
    return 0;
}
5 は行列内に存在します。

2次元配列とポインタを活用することで、行列の加算、転置、探索など、さまざまな応用が可能です。

これらの技術を使うことで、より複雑なデータ構造やアルゴリズムを実装することができます。

まとめ

この記事では、C++における2次元配列とポインタの基本的な使い方から、応用例まで幅広く解説しました。

特に、静的および動的に確保した2次元配列の扱い方や、関数を通じた操作方法、行列の加算や転置、特定の値の探索といった具体的な例を通じて、実践的な知識を提供しました。

これらの技術を活用して、より複雑なデータ構造やアルゴリズムに挑戦してみてください。

関連記事

Back to top button