★可変長配列3(vector)★


ベクタはデータの個数が不明な状況で、データを配列に追加していくケースに向いたコンテナです。

C言語編の「メモリの領域と確保3」で作ったプログラムをベクタを使ったプログラムに改良してみましょう。

C言語編ではファイルの先頭に格納されているデータの個数を読み込み、malloc関数を使って領域を確保した後でデータを読み込みました。

ベクタを使えば、ファイルの先頭にデータの個数が無い状態でも全データを読み込むことが可能です。

プロジェクトを作成し、↓のデータをプロジェクトファイルにコピーしてください。

 Monster2.txt

ファイルに関してはC言語のファイル操作関数を使います。

データ用構造体も前のものと同じなのですが、データ自体が変わっていますので名前の文字列のサイズなど若干変えて作ります。


まずは構造体の宣言とmain関数を作ります。

<sample program cpp015-01>

#include <cstdio>
#include <iostream>
#include <vector>

static const int MAX_NAME = 15;

struct Monster {
    char name[MAX_NAME];
    int attack;
    int defence;
    int hp;
    int experience;
};

int main()
{
    return 0;
}

続いて、ファイルのオープン、クローズを追加しましょう。

<sample program cpp015-02>

#include <cstdio>
#include <iostream>
#include <vector>

static const int MAX_NAME = 15;

struct Monster {
    char name[MAX_NAME];
    int attack;
    int defence;
    int hp;
    int experience;
};

int main()
{
    FILE* fpMonster;

    fpMonster = fopen("Monster2.txt", "r");

    if (!fpMonster) {
        return 1;
    }

    fclose(fpMonster);

    fpMonster = NULL;

    return 0;
}

次に読み込むためのベクタを用意します。

<sample program cpp015-03>

#include <cstdio>
#include <iostream>
#include <vector>

static const int MAX_NAME = 15;

struct Monster {
    char name[MAX_NAME];
    int attack;
    int defence;
    int hp;
    int experience;
};

int main()
{
    std::vector<Monster> vecMonster;

    FILE* fpMonster;

    fpMonster = fopen("Monster2.txt", "r");

    if (!fpMonster) {
        return 1;
    }

    fclose(fpMonster);

    fpMonster = NULL;

    return 0;
}

構造体のベクタはpush_backするために作業領域が必要となりますので追加しましょう。

<sample program cpp015-04>

#include <cstdio>
#include <iostream>
#include <vector>

static const int MAX_NAME = 15;

struct Monster {
    char name[MAX_NAME];
    int attack;
    int defence;
    int hp;
    int experience;
};

int main()
{
    std::vector<Monster> vecMonster;

    FILE* fpMonster;

    fpMonster = fopen("Monster2.txt", "r");

    if (!fpMonster) {
        return 1;
    }

    Monster work;

    fclose(fpMonster);

    fpMonster = NULL;

    return 0;
}

後は読み込みですが、データの個数が分からないのでfeof関数を使ってEOFを検知するまで読み込めるようにします。

作業領域に読み込んだデータはpush_back関数でベクタに追加していきます。

<sample program cpp015-05>

#include <cstdio>
#include <iostream>
#include <vector>

static const int MAX_NAME = 15;

struct Monster {
    char name[MAX_NAME];
    int attack;
    int defence;
    int hp;
    int experience;
};

int main()
{
    std::vector<Monster> vecMonster;

    FILE* fpMonster;

    fpMonster = fopen("Monster2.txt", "r");

    if (!fpMonster) {
        return 1;
    }

    Monster work;

    while (!feof(fpMonster)) {

        fscanf(fpMonster, "%s", work.name);
        fscanf(fpMonster, "%d", &work.attack);
        fscanf(fpMonster, "%d", &work.defence);
        fscanf(fpMonster, "%d", &work.hp);
        fscanf(fpMonster, "%d", &work.experience);

        vecMonster.push_back(work);
    }

    fclose(fpMonster);

    fpMonster = NULL;

    return 0;
}

最後に全データを表示しましょう。

※今回はモンスター名のみ表示します。

<sample program cpp015-06>

#include <cstdio>
#include <iostream>
#include <vector>

static const int MAX_NAME = 15;

struct Monster {
    char name[MAX_NAME];
    int attack;
    int defence;
    int hp;
    int experience;
};

int main()
{
    std::vector<Monster> vecMonster;

    FILE* fpMonster;

    fpMonster = fopen("Monster2.txt", "r");

    if (!fpMonster) {
        return 1;
    }

    Monster work;

    while (!feof(fpMonster)) {

        fscanf(fpMonster, "%s", work.name);
        fscanf(fpMonster, "%d", &work.attack);
        fscanf(fpMonster, "%d", &work.defence);
        fscanf(fpMonster, "%d", &work.hp);
        fscanf(fpMonster, "%d", &work.experience);

        vecMonster.push_back(work);
    }

    fclose(fpMonster);

    fpMonster = NULL;

    for (unsigned int i = 0; i < vecMonster.size(); i++) {
        std::cout << vecMonster[i].name << std::endl;
    }

    return 0;
}

<実行結果>

スライム
アシッドスライム
アーミーアント
バット
ラット
ゴースト
ポイズンスライム
ポイズンバット
キングコブラ
ラージアント
ビッグラット
マジシャン
センチピード
クローラー
ヒュージバット
ミストスライム
マンドリル
リビングデッド
ドラゴンフライ
アーマーラット
メタルスネーク
ゴーストラット
マンイーター
マミー
メドゥーサ
シャーマン
デス
パペット
バブーン
ジェリーフィッシュ
シーカウ
ガーゴイル
プテラノドン
ホークアイ
ポイズンマミー
サーペントウルフ
グレムリン
オーク
バジリスク
ゴーゴンヘッド
ドラゴン
アンデッド
ゴールデンオーク
トレント
マッドハンド
ガストール
ポイズンウッド
ロッティングコープス
ソーサラー
バーサーカー
ヘッドハンター
ブラッディハンド
キラーパペット
サラマンダー
ヒュージマミー
グール
ヘルスカウター
デモンズアイ
キラータイガー
ゴールドハンター
スカルヘッドナイト
ダークネスアイ
バーバリアン
リトルデビル
キングオーク
オウルメイジ
ナイトオブヘル
ドラゴン
シルバーデビル
カオスドラゴン
キラーマシーン
サイクロプス
ブリザード
ギガンテス
デビルロード
アークデーモン
デモンプリースト
タイタン
ベルゼブブ
ベリアル
アザゼル
ルシフェル
続行するには何かキーを押してください・・・

完成しました!

結局データは何個あったのでしょうか?

表示部分を変更して確認しましょう。

<sample program cpp015-06>

#include <cstdio>
#include <iostream>
#include <vector>

static const int MAX_NAME = 15;

struct Monster {
    char name[MAX_NAME];
    int attack;
    int defence;
    int hp;
    int experience;
};

int main()
{
    std::vector<Monster> vecMonster;

    FILE* fpMonster;

    fpMonster = fopen("Monster2.txt", "r");

    if (!fpMonster) {
        return 1;
    }

    Monster work;

    while (!feof(fpMonster)) {

        fscanf(fpMonster, "%s", work.name);
        fscanf(fpMonster, "%d", &work.attack);
        fscanf(fpMonster, "%d", &work.defence);
        fscanf(fpMonster, "%d", &work.hp);
        fscanf(fpMonster, "%d", &work.experience);

        vecMonster.push_back(work);
    }

    fclose(fpMonster);

    fpMonster = NULL;

    std::cout << "モンスターは" << vecMonster.size() << "体です。" << std::endl;

    return 0;
}

<実行結果>

モンスターは82体です。
続行するには何かキーを押してください・・・

ベクタがあればmalloc関数は不要という訳ではありません。

適材適所という事をよく考えてデータ構造を選んでください。


次へ

戻る

目次へ