[C++] 配列の要素数を動的に変更する方法
C++では、標準配列の要素数を動的に変更することはできません。
代わりに、動的メモリ管理を行うnewやdeleteを使用してポインタで配列を作成し直すか、STLのstd::vectorを使用します。
std::vectorは動的配列として機能し、push_backやresizeで要素数を柔軟に変更可能です。
動的メモリ管理を使った配列の要素数変更
C++では、配列のサイズをコンパイル時に固定する必要がありますが、動的メモリ管理を使用することで、実行時に配列のサイズを変更することが可能です。
ここでは、new演算子とdelete演算子を使った動的配列の作成と要素数の変更方法について解説します。
動的配列の作成
まず、動的配列を作成するためには、new演算子を使用します。
以下のサンプルコードでは、整数型の動的配列を作成し、要素に値を代入しています。
#include <iostream>
int main() {
    int size = 5; // 配列の初期サイズ
    int* dynamicArray = new int[size]; // 動的配列の作成
    // 配列に値を代入
    for (int i = 0; i < size; i++) {
        dynamicArray[i] = i + 1; // 1から5までの値を代入
    }
    // 配列の内容を表示
    for (int i = 0; i < size; i++) {
        std::cout << dynamicArray[i] << " "; // 配列の要素を表示
    }
    std::cout << std::endl;
    // メモリの解放
    delete[] dynamicArray; // 動的配列のメモリを解放
    return 0;
}1 2 3 4 5このコードでは、最初に5つの要素を持つ動的配列を作成し、1から5までの値を代入しています。
配列の使用が終わったら、delete[]を使ってメモリを解放することが重要です。
配列の要素数を変更する方法
配列の要素数を変更するためには、新しい配列を作成し、既存の配列の内容をコピーする必要があります。
以下のサンプルコードでは、配列のサイズを変更する方法を示します。
#include <iostream>
#include <cstring> // std::memcpyを使用するために必要
int main() {
    int size = 5; // 初期サイズ
    int* dynamicArray = new int[size]; // 初期の動的配列作成
    // 配列に値を代入
    for (int i = 0; i < size; i++) {
        dynamicArray[i] = i + 1; // 1から5までの値を代入
    }
    // 新しいサイズを設定
    int newSize = 10; // 新しいサイズ
    int* newArray = new int[newSize]; // 新しい動的配列を作成
    // 既存の配列の内容を新しい配列にコピー
    std::memcpy(newArray, dynamicArray, size * sizeof(int)); // 内容をコピー
    // 新しい配列の残りの要素に値を代入
    for (int i = size; i < newSize; i++) {
        newArray[i] = 0; // 残りの要素には0を代入
    }
    // 新しい配列の内容を表示
    for (int i = 0; i < newSize; i++) {
        std::cout << newArray[i] << " "; // 新しい配列の要素を表示
    }
    std::cout << std::endl;
    // メモリの解放
    delete[] dynamicArray; // 古い配列のメモリを解放
    delete[] newArray; // 新しい配列のメモリを解放
    return 0;
}1 2 3 4 5 0 0 0 0 0このコードでは、最初に5つの要素を持つ動的配列を作成し、その後新しいサイズ10の配列を作成して、既存の配列の内容をコピーしています。
残りの要素には0を代入しています。
メモリを解放することも忘れずに行います。
標準ライブラリstd::vectorの活用
C++の標準ライブラリには、動的配列を簡単に扱うためのstd::vectorというクラスがあります。
std::vectorを使用することで、配列のサイズを動的に変更したり、要素の追加や削除を簡単に行うことができます。
ここでは、std::vectorの基本的な使い方とその利点について解説します。
std::vectorの基本的な使い方
std::vectorを使用するには、<vector>ヘッダをインクルードする必要があります。
以下のサンプルコードでは、std::vectorを使って整数の動的配列を作成し、要素を追加する方法を示します。
#include <iostream>
#include <vector> // std::vectorを使用するために必要
int main() {
    std::vector<int> vec; // 空のベクターを作成
    // 要素を追加
    for (int i = 1; i <= 5; i++) {
        vec.push_back(i); // ベクターに要素を追加
    }
    // ベクターの内容を表示
    for (size_t i = 0; i < vec.size(); i++) {
        std::cout << vec[i] << " "; // ベクターの要素を表示
    }
    std::cout << std::endl;
    return 0;
}1 2 3 4 5このコードでは、std::vectorを使って整数のベクターを作成し、push_backメソッドを使って要素を追加しています。
vec.size()で現在の要素数を取得し、ループで表示しています。
要素の削除とサイズの変更
std::vectorでは、要素の削除も簡単に行えます。
以下のサンプルコードでは、特定の要素を削除し、ベクターのサイズを変更する方法を示します。
#include <iostream>
#include <vector> // std::vectorを使用するために必要
int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5}; // 初期値を持つベクターを作成
    // ベクターの内容を表示
    std::cout << "初期のベクター: ";
    for (size_t i = 0; i < vec.size(); i++) {
        std::cout << vec[i] << " "; // ベクターの要素を表示
    }
    std::cout << std::endl;
    // 要素を削除
    vec.erase(vec.begin() + 2); // インデックス2の要素を削除
    // 削除後のベクターの内容を表示
    std::cout << "削除後のベクター: ";
    for (size_t i = 0; i < vec.size(); i++) {
        std::cout << vec[i] << " "; // ベクターの要素を表示
    }
    std::cout << std::endl;
    return 0;
}初期のベクター: 1 2 3 4 5 
削除後のベクター: 1 2 4 5このコードでは、初期値を持つベクターを作成し、eraseメソッドを使ってインデックス2の要素(3)を削除しています。
削除後のベクターの内容を表示することで、要素が正しく削除されたことを確認できます。
std::vectorの利点
std::vectorを使用することには、以下のような利点があります。
| 利点 | 説明 | 
|---|---|
| 自動メモリ管理 | メモリの確保と解放を自動で行うため、手動での管理が不要。 | 
| サイズの動的変更 | 要素の追加や削除が簡単で、サイズを動的に変更可能。 | 
| STLの機能との統合 | 他のSTLアルゴリズムやデータ構造と簡単に組み合わせて使用できる。 | 
std::vectorは、動的配列を扱う際の強力なツールであり、C++プログラミングにおいて非常に便利です。
動的配列とstd::vectorの比較
C++における動的配列とstd::vectorは、どちらも動的にサイズを変更できる配列ですが、それぞれに特徴と利点があります。
ここでは、両者の違いを比較し、どのような場面でそれぞれを使用すべきかを解説します。
メモリ管理の違い
| 特徴 | 動的配列 | std::vector | 
|---|---|---|
| メモリの確保 | new演算子を使用して手動で行う | 自動で行われる | 
| メモリの解放 | delete[]を使用して手動で行う | 自動で行われる | 
| メモリの再確保 | 手動で新しい配列を作成し、コピーする必要がある | 自動でサイズ変更が可能 | 
動的配列では、メモリの確保と解放を手動で行う必要がありますが、std::vectorではこれらが自動で管理されます。
これにより、メモリリークのリスクが低減します。
サイズ変更の容易さ
| 特徴 | 動的配列 | std::vector | 
|---|---|---|
| サイズ変更 | 新しい配列を作成し、内容をコピーする必要がある | push_backやresizeで簡単に変更可能 | 
| 要素の追加 | 手動で新しい配列を作成する必要がある | push_backで簡単に追加可能 | 
| 要素の削除 | 手動で要素を削除し、配列を再構築する必要がある | eraseで簡単に削除可能 | 
動的配列では、サイズを変更する際に手動で新しい配列を作成し、既存の要素をコピーする必要があります。
一方、std::vectorでは、要素の追加や削除が非常に簡単に行えます。
使用の簡便さ
| 特徴 | 動的配列 | std::vector | 
|---|---|---|
| コードの簡潔さ | 複雑なメモリ管理が必要 | シンプルで直感的なインターフェース | 
| エラーハンドリング | 手動で行う必要がある | 自動で行われる | 
| STLとの統合 | 他のSTLコンテナとの組み合わせが難しい | 他のSTLアルゴリズムと簡単に統合可能 | 
std::vectorは、C++の標準ライブラリの一部であり、他のSTLコンテナやアルゴリズムと簡単に統合できます。
動的配列は、手動でのメモリ管理が必要なため、コードが複雑になりがちです。
動的配列とstd::vectorは、それぞれ異なる利点を持っていますが、一般的にはstd::vectorを使用することが推奨されます。
特に、メモリ管理の自動化やサイズ変更の容易さ、他のSTLコンテナとの統合のしやすさから、std::vectorは多くの場面で便利です。
ただし、特定のパフォーマンス要件やメモリ制約がある場合には、動的配列を選択することも考慮すべきです。
実践例:動的配列の活用
動的配列は、サイズが不明なデータを扱う際に非常に便利です。
ここでは、動的配列を使用して、ユーザーからの入力を受け取り、動的にサイズを変更しながらデータを格納する実践的な例を示します。
この例では、ユーザーが入力した整数を動的配列に格納し、最終的にその内容を表示します。
以下のコードでは、ユーザーが入力した整数を動的配列に格納し、”0″が入力されるまで続けます。
配列のサイズは、必要に応じて動的に変更されます。
#include <iostream>
int main() {
    int* dynamicArray = nullptr; // 動的配列のポインタ
    int size = 0; // 現在の配列のサイズ
    int capacity = 2; // 初期容量
    dynamicArray = new int[capacity]; // 初期の動的配列を作成
    std::cout << "整数を入力してください(0で終了):" << std::endl;
    while (true) {
        int input;
        std::cin >> input; // ユーザーからの入力を受け取る
        if (input == 0) { // 0が入力されたら終了
            break;
        }
        // 配列のサイズが容量を超えた場合、容量を倍にする
        if (size >= capacity) {
            capacity *= 2; // 容量を倍にする
            int* newArray = new int[capacity]; // 新しい配列を作成
            
            // 既存の配列の内容を新しい配列にコピー
            for (int i = 0; i < size; i++) {
                newArray[i] = dynamicArray[i]; // 内容をコピー
            }
            delete[] dynamicArray; // 古い配列のメモリを解放
            dynamicArray = newArray; // ポインタを新しい配列に更新
        }
        dynamicArray[size] = input; // 入力された値を配列に格納
        size++; // サイズを増加
    }
    // 入力された整数を表示
    std::cout << "入力された整数:" << std::endl;
    for (int i = 0; i < size; i++) {
        std::cout << dynamicArray[i] << " "; // 配列の要素を表示
    }
    std::cout << std::endl;
    // メモリの解放
    delete[] dynamicArray; // 動的配列のメモリを解放
    return 0;
}- 初期設定: 動的配列のポインタをnullptrで初期化し、初期容量を2に設定します。
最初の動的配列を作成します。
- ユーザー入力: ユーザーから整数を入力させ、”0″が入力されるまでループします。
- 容量の確認: 配列のサイズが現在の容量を超えた場合、容量を倍にし、新しい配列を作成します。
既存の配列の内容を新しい配列にコピーし、古い配列のメモリを解放します。
- データの格納: 入力された整数を動的配列に格納し、サイズを増加させます。
- 結果の表示: 最後に、入力された整数を表示します。
- メモリの解放: 使用が終わった動的配列のメモリを解放します。
整数を入力してください(0で終了):
5
10
15
0
入力された整数:
5 10 15この実践例では、動的配列を使用して、ユーザーからの入力を効率的に管理しています。
配列のサイズを動的に変更することで、必要なメモリを確保し、プログラムの柔軟性を高めています。
動的配列は、サイズが不明なデータを扱う際に非常に有用です。
配列の要素数変更における注意点
配列の要素数を変更する際には、いくつかの注意点があります。
特に、動的配列やstd::vectorを使用する場合でも、メモリ管理やデータの整合性に関して気を付けるべきポイントがあります。
以下に、配列の要素数変更における主な注意点をまとめます。
1. メモリリークの防止
動的配列を使用する場合、メモリの確保と解放を手動で行う必要があります。
新しい配列を作成した際には、古い配列のメモリを解放しないと、メモリリークが発生します。
以下の点に注意してください。
- 新しい配列を作成したら、必ず古い配列のメモリをdelete[]で解放する。
- std::vectorを使用する場合は、メモリ管理が自動で行われるため、メモリリークの心配は少ない。
2. データのコピー
配列のサイズを変更する際には、既存のデータを新しい配列にコピーする必要があります。
この際、以下の点に注意してください。
- コピーする際には、配列のサイズを正しく指定すること。
誤ってサイズを間違えると、データが失われたり、未定義の動作を引き起こす可能性がある。
- std::memcpyを使用する場合、コピーするバイト数を正確に計算することが重要です。
3. 配列の境界チェック
配列の要素数を変更する際には、配列の境界を超えないように注意が必要です。
特に、手動でメモリ管理を行う場合、以下の点に気を付けましょう。
- 配列のインデックスが有効な範囲内であることを確認する。
無効なインデックスにアクセスすると、未定義の動作を引き起こす。
- std::vectorを使用する場合、- at()メソッドを使うことで、境界チェックを行うことができる。
4. パフォーマンスの考慮
配列のサイズを頻繁に変更する場合、パフォーマンスに影響を与えることがあります。
以下の点を考慮してください。
- 動的配列を使用する場合、サイズ変更のたびに新しい配列を作成し、データをコピーするため、オーバーヘッドが発生する。
頻繁なサイズ変更が予想される場合は、初期容量を大きめに設定することを検討する。
- std::vectorは、内部で容量を自動的に管理しますが、サイズ変更が頻繁に行われる場合、パフォーマンスに影響を与えることがあります。
必要に応じて、reserve()メソッドを使用して、事前に容量を確保することができます。
5. 例外処理
配列のサイズ変更中にエラーが発生する可能性があります。
特に、メモリの確保に失敗した場合、プログラムがクラッシュすることがあります。
以下の点に注意してください。
- メモリの確保に失敗した場合のエラーハンドリングを行う。
new演算子を使用する際には、例外をキャッチすることが重要です。
- std::vectorを使用する場合、メモリ管理が自動で行われるため、例外処理が簡単になりますが、サイズ変更時の例外に備えることも重要です。
配列の要素数を変更する際には、メモリ管理やデータの整合性、パフォーマンスに関する注意点を理解しておくことが重要です。
動的配列やstd::vectorを適切に使用することで、これらの問題を軽減し、効率的なプログラムを作成することができます。
特に、std::vectorは自動的なメモリ管理を提供するため、一般的にはこちらを使用することが推奨されます。
まとめ
この記事では、C++における配列の要素数を動的に変更する方法について、動的メモリ管理やstd::vectorの活用、実践例、注意点を詳しく解説しました。
動的配列とstd::vectorの違いや、それぞれの利点を理解することで、適切な場面での使い分けが可能になります。
今後は、これらの知識を活かして、より効率的で柔軟なプログラムを作成してみてください。
 
![[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)
![[C++] 配列の要素を全て0で初期化する方法](https://af-e.net/wp-content/uploads/2024/10/thumbnail-47448.png)