つくる 配列で成績管理
人数を先に聞いてから、全員を配列に持つ
第4章の「つくる」では、N人ぶんの点数を入力しながらその場で足していきました。あのやり方では、入力が終わった時点で個々の点数は消えています。合計と平均は出せても、「最高点は何点か」には答えられませんでした。
配列を覚えた今なら、入力した点数を全部残しておけます。残っていれば、合計でも最高点でも、あとから何度でも数え直せます。これがこの章でいちばん大きな前進です。
大きめに確保して、使う数だけ回す
配列の個数は、コンパイル時に決まっている必要があります。人数は実行してから分かるので、先に十分な大きさを確保しておき、実際に使う数を変数で持ちます。
#define MAX_STUDENTS 100
int scores[MAX_STUDENTS];
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d", &scores[i]);
}確保した数が 100 でも、ループは i < n で回します。i < MAX_STUDENTS にしてしまうと、入力していない箱まで読むことになり、中身の分からない値が集計に混ざります。
確保した大きさと、実際に使っている数は別という考え方は、前回の文字列でも出てきました。char 配列の箱の大きさと strlen の返す長さの関係とまったく同じです。C ではこの2つを自分で管理し続ける必要があります。
集計は入力とは別のループで
入力のループの中で合計や最高点を求めることもできますが、この章では役目ごとにループを分けます。
- 入力するループ
- 合計を出すループ
- 最高点を探すループ
分けておくと、あとから「最低点も出したい」となったときにループを1つ足すだけで済みます。データが配列に残っているからこそできる書き方です。
最高点の初期値は 0 ではなく scores[0] にします。今回の題材は点数なので 0 でも動いてしまいますが、その癖のままマイナスを含むデータを扱うと必ず事故ります。
平均は (double)total / n としてキャストを忘れないでください。n は入力から来る値なので、total / n と書くと切り捨てになります。
人数が0だとどうなるか
実務のコードなら、n が 0 のときの手当ても要ります。0 で割ると答えが定まらず、scores[0] も入力されていない箱を読むことになるからです。
if (n <= 0) {
printf("データがありません\n");
return 0;
}第3章の分岐で、集計に入る前に弾いてしまうのが定石です。今回の課題では人数が1以上の入力しか来ませんが、こういう「起きたら困る入力」を先に潰しておく考え方は、章が進むほど効いてきます。同じ理由で、n が MAX_STUDENTS を超えていないかも本来は確かめます。
この章を終えると、成績管理CLI は「人数を聞いて、全員ぶんを覚えて、何度でも数え直せる」ところまで来ます。あとは名前と点数をばらばらの配列で持つのをやめて、1人ぶんをひとまとまりにしたくなるはずです。それが第8章の構造体です。
では、第6章の総仕上げとして、人数ぶんの成績を配列で管理してみましょう。
要件
- 1つ目の入力が人数、続く入力が人数ぶんの点数
- 3人ぶんの点数を登録しました の形で人数を表示する
- 合計は237点です の形で合計を表示する
- 平均は79.0点です の形で、小数第1位まで表示する
- 最高点は92点です の形で最高点を表示する
入出力例
main("3", "80 65 92") → "3人ぶんの点数を登録しました
合計は237点です
平均は79.0点です
最高点は92点です"
main("5", "60 70 80 90 100") → "5人ぶんの点数を登録しました
合計は400点です
平均は80.0点です
最高点は100点です"