ファイルを読み込む
保存したものを変数に戻す
前回、成績を scores.txt に「名前 点数」の形で書き出しました。今回はその逆をやります。ファイルの文字を読み取って、struct Student の配列に戻します。ここまでできて初めて、前回の続きから使える成績管理CLI になります。
開き方は同じ fopen で、モードだけ "r" にします。
fp = fopen("scores.txt", "r");読むだけなので、既にある中身が消えることはありません。
scanf のファイル版
読み取りには fscanf を使います。scanf の先頭に fp を足しただけです。
fscanf(fp, "%31s %d", list[i].name, &list[i].score);書式の意味も & の付け方も scanf と同じです。%s は空白か改行までを 1 つの単語として読み、%d は数字を読みます。前回わざと「名前 点数」を空白で区切って 1 行ずつ書いたのは、この読み方にぴったり合う形だからです。
どこで止めるか
キーボードからの入力と違い、ファイルには終わりがあります。何人分入っているか分からないファイルを読むには、終わりを検知して止まる 仕組みが要ります。
ここで fscanf の 戻り値 を使います。fscanf は「書式のうち何個ぶん読み取れたか」を返します。"%31s %d" なら成功時は 2 です。ファイルの終わりに来ると読み取れる項目が無くなるので、2 より小さい値が返ります。
while (count < 3 && fscanf(fp, "%31s %d", list[count].name, &list[count].score) == 2) {
count = count + 1;
}この while は「2 個読めたら次へ、読めなくなったら抜ける」と読みます。抜けたときの count が、そのまま読み込めた人数です。人数を別のどこかに書いておかなくても、数えながら読めば分かるわけです。
count < 3 を前に置いているのは、配列の枠より多くファイルに入っていたときにはみ出さないためです。前章で学んだ配列の範囲外アクセスは、ファイルから読むときにも起こります。
1回の実行で書いて読む
今回の課題では、まず入力された 3 人分をファイルに書き出し、そのあと自分で書いたファイルを読み戻します。読み込みだけを試したいところですが、前に実行したときのファイルが必ず残っている保証はありません。書いてから読む形にしておけば、どんな状況でも同じ結果になります。
要件
- scores.txt を読み込みモードで開く
- fscanf の戻り値が2の間だけループして list に読み込む
- 読み込んだ人数を count に数える
- 一覧を「田中 82点」の形で表示し、最後に「3人の平均は81点です」の形で表示する
入出力例
main("田中 82", "佐藤 90", "鈴木 71") → "田中 82点
佐藤 90点
鈴木 71点
3人の平均は81点です"
main("高橋 60", "伊藤 70", "渡辺 80") → "高橋 60点
伊藤 70点
渡辺 80点
3人の平均は70点です"