つくる 動的Student完成

この章でやったことを 1 つにまとめる

第 4 章では、構造体をポインタで触る ->、構造体をヒープに置く malloc(sizeof(Student))、人数ぶんまとめて借りる動的な構造体配列、表示のしかたを差し替える関数ポインタ、そして qsort による並べ替えを見てきました。今回は全部を 1 つのプログラムに入れて、成績管理の一覧部分を作り直します。

作るもの

入力は次の形で来ます。1 行目が表示のしかた、2 行目が人数、そのあとに人数ぶんの 名前 点数 が並びます。

1 4 Sato 80 Suzuki 95 Tanaka 80 Ito 73

やることは 4 つです。人数ぶんの Student をヒープに確保して読み込み、点数の高い順に並べ替え、指定された形式で全員を表示し、最後に平均を小数第 1 位まで出します。表示のしかたは 1 なら 名前 点数、2 なら名前のあとに 点数 / 10 個の * を並べた棒グラフです。

並びを一意にしておく

上の例では Sato と Tanaka が同点です。点数だけで比べると、この 2 人のどちらが先に出るかは決まりません。前回書いたように、点数が等しいときは名前で比べて、並びが一意になるところまで決めてください。この例では Sato が先です。

表示の選び方

if で表示を分けるのではなく、先に関数ポインタへどちらかを入れてから、ループの中では選んだものを呼ぶ形にしてください。

void (*style)(const Student *) = print_plain; if (mode == 2) { style = print_bar; }

こうしておくと、ループの中に判定が残りません。表示の種類が増えても、増えるのは if の枝だけでループは変わりません。

平均の出し方

点数は int なので、そのまま足して n で割ると小数が切り捨てられます。片方を double にしてから割ってください。表示は %.1f にします。%f のままだと小数第 6 位まで出ます。

printf("平均 %.1f\n", (double)sum / n);

後始末

malloc は 1 回なので free も 1 回です。表示や並べ替えが終わったあと、return の前に解放します。プログラムが終われば OS が回収してくれますが、この形をそのまま関数に切り出したときにリークが残るので、いまのうちから書く癖を付けておいてください。

入門の成績管理と何が変わったか

入門で書いた版は Student list[100]; のような固定長配列でした。100 人を超える入力は受け取れず、逆に 3 人しか使わない日でも 100 人ぶんの領域を抱えていました。人数の上限がコードに焼き付いていたわけです。

今回の版には上限がありません。人数は実行時に決まり、必要なぶんだけ借ります。並べ替えも自分で書かず、大小の決め方だけを渡して qsort にやらせています。表示のしかたも走査から切り離しました。同じ「成績を一覧する」という仕事でも、どこを実行時に決められるようにするかで、コードの形はここまで変わります。

残っている弱点は、途中に 1 人だけ挿入したいときです。動的配列は連続して並んでいるので、間に入れるには後ろを全部ずらすことになります。次の第 5 章では、ここを付け替えだけで済ませる連結リストに作り替えていきます。

要件

  1. 人数分の Student をヒープに確保して読み込む
  2. 確保に失敗したら「確保できませんでした」と表示して return 1 する
  3. qsort で点数の高い順に並べ替える。同点なら名前の辞書順にする
  4. 1行目が 2 なら print_bar、それ以外なら print_plain を関数ポインタに入れて使う
  5. 最後に「平均 」に続けて平均点を小数第1位まで表示する
  6. 確保した領域を free する

入出力例

main("1 4 Sato 80 Suzuki 95 Tanaka 80 Ito 73") → "Suzuki 95 Sato 80 Tanaka 80 Ito 73 平均 82.0" main("2 3 Mori 88 Aoki 60 Endo 60") → "Mori ******** Aoki ****** Endo ****** 平均 69.3"

ヒント

生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア
編集 LuaGate編集部
main.c
学習モード

メモ

つくる 動的Student完成

⌘S で保存