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参照を使い、データをコピーせず、変更しない形で読んでいます。
改造してみよう
一つずつ追加すると、さらに練習できます。
- 全員の合計点と平均点を表示する
- 最高点の人を表示する
- 合格点をconst変数へまとめる
- 名前に空白を含められるようにする
- メニューを作り、入力と表示を何度も選べるようにする
最初から全部追加する必要はありません。一つ変更したら実行し、動作を確認してから次へ進みましょう。
模範解答
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++超入門① 最初のプログラムを書いて動かそう