つくる 入力処理の関数化
main が長くなってきました
第6章の成績管理は、入力の for 文、合計を出す for 文、最高点を探す for 文が、すべて main の中に並んでいました。動きはしますが、main を読んでも全体の流れが見えません。
第5章で学んだとおり、まとまった仕事は関数に切り出します。今回は次の 2 つに分けます。
void input_scores(int scores[], int n);
void summarize(const int scores[], int n, int *total, int *best);input_scores は配列を受け取って、そこへ点数を読み込みます。前回のとおり配列は番地で渡るので、関数の中で入れた値がそのまま呼び出し元の配列に残ります。
summarize が今回の山場です。返したい結果が合計と最高点の 2 つあるので、return では足りません。そこで結果を受け取る変数の番地を int *total と int *best で受け取り、*total = ... の形で呼び出し元へ書き込みます。関数の中では * を付けるのを忘れないでください。
main はどうなるか
int scores[COUNT];
int total, best;
input_scores(scores, COUNT);
summarize(scores, COUNT, &total, &best);main に残るのは 4 行と表示だけになりました。読むだけで「入力して、集計して、表示する」と分かります。第6章の版と見比べると、行数はそれほど減っていないのに読みやすさは大きく変わっています。関数に切り出す価値は、短くすることではなく、名前を付けて役割を分けることにあります。
平均の型に注意
平均は第2章で扱った整数除算の罠がそのまま出ます。total / COUNT は切り捨てになるので、(double)total / COUNT と書いて %.1f で表示します。
書き換える関数には int scores[]、読むだけの関数には const int scores[] を付けておくと、うっかり事故を減らせます。summarize は配列を読むだけで、書き込むのは合計と最高点の 2 つだけ、ということが宣言を見ただけで分かる形になっています。
ここまでが基礎編のポインタ
第7章で扱ったのは、& で番地を取る、* で指す先を読み書きする、関数の引数として渡す、この 3 つだけです。C のポインタには、番地に足し算をして隣の要素へ進むポインタ演算や、必要な分だけメモリを実行中に確保する malloc といった話も続きますが、それらは中級コースへ回します。基礎編では、いま書けるようになった「呼び出し元の変数を関数から書き換える」を確実に手に入れてください。次の第8章では、この考え方のまま構造体とファイルへ進みます。
では、4 人分の成績を集計するプログラムを完成させましょう。
要件
- input_scores で 4 つの点数を配列に読み込む
- void summarize(const int scores[], int n, int *total, int *best) を完成させる
- 合計を 「合計は326点です」 の形で表示する
- 最高点を 「最高点は95点です」 の形で表示する
- 平均を 「平均は81.5点です」 の形で小数第1位まで表示する
入出力例
main("80 95 70 81") → "合計は326点です
最高点は95点です
平均は81.5点です"
main("100", "100", "100", "100") → "合計は400点です
最高点は100点です
平均は100.0点です"
main("60 72 88 64") → "合計は284点です
最高点は88点です
平均は71.0点です"