本文へスキップ
BecomeCoder

C言語コース · 第11章 ファイル入出力 · レッスン43

fprintf/fscanf ― 書式付きでファイルに読み書きする

ブラウザで完結

導入

printf は画面に、scanf は標準入力から、書式(%d%s)を指定して読み書きする関数でした。実は printf は「stdout(標準出力)という特別なファイルに書き込む fprintf」の省略形にすぎません。同じ考え方で、普通のファイルに対しても書式付きの読み書きができます。

説明

  • fprintf(fp, "書式", 値...)printf と同じ書式指定子がそのまま使えます。書き込み先をファイルポインタ fp で指定するだけの違いです。
  • fscanf(fp, "書式", &変数...)scanf と同じ書式指定子で、ファイルから読み込みます。

fscanf の戻り値は「正しく読み取れた項目の数」です。ファイルの終端に達すると、期待した項目数より少ない値(あるいは EOF)が返るので、while (fscanf(...) == 項目数) { ... } という形でファイルを最後まで読み進めるのが定番のパターンです。

#include <stdio.h>

int main(void) {
    FILE *fp = fopen("/home/user/score.txt", "w");
    if (fp == NULL) {
        printf("書き込み用に開けませんでした\n");
        return 1;
    }
    fprintf(fp, "%s %d\n", "Taro", 85);
    fprintf(fp, "%s %d\n", "Hanako", 92);
    fclose(fp);
    printf("書き込み完了\n");

    fp = fopen("/home/user/score.txt", "r");
    if (fp == NULL) {
        printf("読み込み用に開けませんでした\n");
        return 1;
    }
    char name[32];
    int score;
    while (fscanf(fp, "%s %d", name, &score) == 2) {
        printf("%sさんの得点は%dです\n", name, score);
    }
    fclose(fp);
    return 0;
}

%s は空白(スペースや改行)で区切られた1つの単語を読み取り、char配列に格納します。配列は & を付けずにそのまま渡すのがポイントです(配列名はすでに先頭アドレスを表すため)。一方、int などの変数scanf のときと同様に &score のようにアドレスを渡します。

やってみよう

得点をもう1人分追記して、3行とも表示されることを確認しましょう。書式を %d(整数)から %f(小数)に変え、書き込む値も小数に変えると何が起こるか試してみてください。

演習

名前と年齢を1組、fprintf でファイルに書き込み、fscanf で読み込んで「〇〇さんは△△歳です」の形式で表示してください。

ヒント1を見る

fprintf(fp, "%s %d\n", "Yamada", 20); のように書き込みます。

ヒント2を見る

読み込みは char name[32]; int age; fscanf(fp, "%s %d", name, &age);。名前の配列には & を付けません。

実際に動かしてみよう

下のエディタにCを書いて「コンパイル & 実行」を押すと、ブラウザ内で本物のCコンパイラ(clang + dlmalloc)がその場でコンパイルして実行し、出力が表示されます。構造体・共用体・malloc/free・関数ポインタ・ファイル入出力などがそのまま動きます。本文の例を書き換えて試しながら進めましょう(初回だけコンパイラの読み込みに時間がかかります。以降はキャッシュされます。この回は標準入力(scanf)は使わず、値はコードに直接書きます)。

C/C++ — ブラウザ内で本物のコンパイラで実行

ブラウザ内で本物のC/C++コンパイラ(clang + libc++ / WebAssembly)を動かします。構造体・malloc/free・std::string・vector・クラス・テンプレート・STL などがそのまま実行できます(初回のみコンパイラの読み込みに時間がかかります。以降はブラウザにキャッシュされます)。
スクロールして表示された時点でも自動で読み込まれます。