本文へスキップ
BecomeCoder

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

fgets ― 1行ずつ読み込む

ブラウザで完結

導入

fscanf は空白区切りの決まった形式を読むのに向いていますが、「1行まるごと」を読みたいとき(空白を含む文章や、行数が事前に分からないファイルなど)には fgets が向いています。

説明

fgets(buf, sizeof(buf), fp) は、fp から改行文字までの1行を(改行文字も含めて)配列 buf に読み込みます。第2引数に sizeof(buf) を渡すことで「バッファの大きさを超えて書き込まない」よう守ってくれます。ファイルの終端に達すると NULL を返すので、

while (fgets(buf, sizeof(buf), fp) != NULL) {
    // 1行ずつの処理
}

という形が「ファイルを最後まで1行ずつ処理する」定番のパターンです。

flowchart TB
  start["fopen(path, \"r\")"] --> loop{"fgets(line, size, fp)\nがNULLでない?"}
  loop -->|Yes| proc["1行処理して表示"] --> loop
  loop -->|No(ファイル終端)| close["fclose(fp)"]
#include <stdio.h>

int main(void) {
    FILE *fp = fopen("/home/user/diary.txt", "w");
    if (fp == NULL) {
        printf("書き込み用に開けませんでした\n");
        return 1;
    }
    fputs("今日は晴れ\n", fp);
    fputs("公園を散歩した\n", fp);
    fputs("夜はカレーを食べた\n", fp);
    fclose(fp);

    fp = fopen("/home/user/diary.txt", "r");
    if (fp == NULL) {
        printf("読み込み用に開けませんでした\n");
        return 1;
    }
    char line[100];
    int lineNo = 1;
    while (fgets(line, sizeof(line), fp) != NULL) {
        printf("%d行目: %s", lineNo, line);
        lineNo++;
    }
    fclose(fp);
    return 0;
}

fgets が読み込んだ line には改行文字 \n がそのまま残っています。だから printf("%d行目: %s", lineNo, line); では line の後ろに \n を追加していません(すでに含まれているため)。

やってみよう

日記の行を増やしたり内容を変えたりしてみましょう。char line[100]char line[5] のように小さくすると、1行が途中で分断されて複数回に分けて読み込まれる様子も確認してみてください(バッファが小さいとどうなるかという実験です)。

演習

好きな3つの単語を1行に1つずつ fputs でファイルに書き込み、fgets で1行ずつ読み込んで「1: 単語」のような形式(行番号付き)で表示してください。

ヒント1を見る

fputs("りんご\n", fp); のように3回書き込みます。

ヒント2を見る

読み込みは int n = 1; while (fgets(line, sizeof(line), fp) != NULL) { printf("%d: %s", n, line); n++; }

実際に動かしてみよう

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

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

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