プログラミング

C++超入門⑩ 点数管理プログラムを完成させよう

変数、if文、while文、for文、関数、vector、構造体、参照を組み合わせ、複数人の点数を管理するプログラムを作ります。

最終回では、ここまで学んだ文法を組み合わせて、小さな点数管理プログラムを作ります。

すべてを一度に書こうとせず、「データをまとめる」「入力する」「結果を表示する」の順に組み立てます。

作るプログラム

次の機能を持つプログラムを作ります。

  • 人数を入力する
  • 名前と0〜100点の点数を入力する
  • 入力した人をvectorへ保存する
  • 60点以上なら合格と表示する

完成したコード

#include <iostream>
#include <string>
#include <vector>

struct Student {
    std::string name;
    int score;
};

void showResult(const Student& student) {
    std::cout << student.name << ": "
              << student.score << "点 ";

    if (student.score >= 60) {
        std::cout << "合格\n";
    } else {
        std::cout << "もう一度復習しましょう\n";
    }
}

int main() {
    int count = 0;
    std::cout << "人数を入力してください: ";
    std::cin >> count;

    std::vector<Student> students;

    for (int i = 0; i < count; i++) {
        Student student;

        std::cout << i + 1 << "人目の名前: ";
        std::cin >> student.name;

        student.score = -1;

        while (student.score < 0 || student.score > 100) {
            std::cout << "0〜100の点数: ";
            std::cin >> student.score;
        }

        students.push_back(student);
    }

    std::cout << "\n結果\n";

    for (const Student& student : students) {
        showResult(student);
    }

    return 0;
}

最初はそのまま入力して動かしてください。動いた後で、部分ごとの役割を確認します。

データを構造体へまとめる

struct Student {
    std::string name;
    int score;
};

名前と点数は、同じ学生に関係するデータです。Student構造体へまとめると、別々の変数で管理するより関係が分かりやすくなります。

表示処理を関数へ分ける

void showResult(const Student& student)

結果表示をshowResult関数へ分けています。

const Student&で受け取ることで、元のStudentをコピーせず、変更もしない形で読めます。

関数の中ではif文を使い、60点以上かどうかで表示を変えています。

vectorへ学生を追加する

std::vector<Student> students;
students.push_back(student);

studentsはStudent型の値を複数保存するvectorです。

名前と点数を入力し終えたstudentを、push_backで最後へ追加します。

while文で入力を確認する

while (student.score < 0 || student.score > 100) {
    std::cout << "0〜100の点数: ";
    std::cin >> student.score;
}

点数が0未満、または100より大きい間は入力を続けます。

条件の**||**は「または」です。0〜100の範囲へ入ると条件がfalseになり、while文を抜けます。

このプログラムでは数字の入力を前提にしています。文字が入力された場合の処理は、入力エラーの扱いを学ぶと追加できます。

範囲for文で結果を表示する

for (const Student& student : students) {
    showResult(student);
}

studentsに入っているStudentを一人ずつ取り出し、showResult関数へ渡します。

ここでもconst参照を使い、データをコピーせず、変更しない形で読んでいます。

改造してみよう

一つずつ追加すると、さらに練習できます。

  1. 全員の合計点と平均点を表示する
  2. 最高点の人を表示する
  3. 合格点をconst変数へまとめる
  4. 名前に空白を含められるようにする
  5. メニューを作り、入力と表示を何度も選べるようにする

最初から全部追加する必要はありません。一つ変更したら実行し、動作を確認してから次へ進みましょう。

模範解答

5つの改造をまとめて反映した例です。

#include <iostream>
#include <limits>
#include <string>
#include <vector>

const int PASS_SCORE = 60;

struct Student {
    std::string name;
    int score;
};

Student inputStudent() {
    Student student;

    std::cin.ignore(
        std::numeric_limits<std::streamsize>::max(), '\n'
    );
    std::cout << "名前: ";
    std::getline(std::cin, student.name);

    student.score = -1;
    while (student.score < 0 || student.score > 100) {
        std::cout << "0〜100の点数: ";
        std::cin >> student.score;
    }

    return student;
}

void showResults(const std::vector<Student>& students) {
    if (students.empty()) {
        std::cout << "まだデータがありません。\n";
        return;
    }

    int total = 0;
    const Student* highest = &students[0];

    for (const Student& student : students) {
        total += student.score;

        if (student.score > highest->score) {
            highest = &student;
        }

        std::cout << student.name << ": " << student.score << "点 ";
        if (student.score >= 80) {
            std::cout << "優\n";
        } else if (student.score >= PASS_SCORE) {
            std::cout << "可\n";
        } else {
            std::cout << "不合格\n";
        }
    }

    double average = static_cast<double>(total) / students.size();
    std::cout << "合計: " << total << "点\n";
    std::cout << "平均: " << average << "点\n";
    std::cout << "最高点: " << highest->name
              << "さん " << highest->score << "点\n";
}

int main() {
    std::vector<Student> students;
    int menu = -1;

    while (menu != 0) {
        std::cout << "\n1: 入力  2: 表示  0: 終了\n";
        std::cout << "選択: ";
        std::cin >> menu;

        if (menu == 1) {
            students.push_back(inputStudent());
        } else if (menu == 2) {
            showResults(students);
        } else if (menu != 0) {
            std::cout << "0〜2を選んでください。\n";
        }
    }

    return 0;
}

解説

totalへ全員の点数を加え、人数で割って平均を求めています。highestには現在の最高点の学生を指すポインタを保存し、より高い点数が見つかったときに更新します。

合格点はPASS_SCOREへまとめたため、基準を変えるときは1か所の修正で済みます。名前はgetlineで1行受け取るので空白を含められます。メニュー全体をwhile文で囲み、0が選ばれるまで入力と表示を繰り返します。

ここまでで作れるもの

このシリーズで学んだ内容を組み合わせると、次のような小さなプログラムを作れます。

  • 簡単な電卓
  • 数当てゲーム
  • 買い物の合計計算
  • ゲームキャラクターの状態管理
  • 学生や商品の一覧管理

エラーが出ても、書いたコードがすべて間違っているわけではありません。表示された行の近くを読み、一つずつ直すことがプログラミングの練習になります。

まとめ

  • 構造体とvectorで、複数人のデータをまとめられます。
  • if文、while文、for文を組み合わせると、判断と繰り返しを作れます。
  • 関数へ処理を分けると、長いコードを読みやすくできます。

前の記事:C++超入門⑨ クラスの基本を知ろう

最初から復習する:C++超入門① 最初のプログラムを書いて動かそう

C++シリーズの記事をまとめて見る

← 記事一覧へ戻る