C言語入門|1文字列をまとめて読み書きする:fputsとfgets

1文字ずつから、ひとかたまりへ

これまでの記事では、ファイル入出力の基本として、

  • ファイルのオープンとクローズ
  • 1文字ずつ読み書きする方法

を体験してきました。

1文字単位の入出力は仕組みが分かりやすい反面、
文字数が多くなると、どうしても処理が増えてしまいます。

そこで今回は、
文字列をまとめて扱える便利な関数 を紹介します。

fputs と fgets の役割

文字列単位でファイル入出力を行う代表的な関数が、次の2つです。

関数名役割
fputs文字列をまとめてファイルに書き込む。
fgetsファイルから1行分の文字列を読み取る。

どちらも stdio.h に定義されており、
テキストファイルの読み書きで非常によく使われます。

文字列をまとめて書き、1行ずつ読む例

次のプログラムは、

  1. 複数行の文字列をまとめてファイルへ書き込み
  2. そのファイルを1行ずつ読み取り
  3. 画面に表示する

という処理を行います。

サンプルプログラム

プロジェクト名:14-7-1 ソースファイル名: sample14-7-1.c

Visual Studio でこのプログラムを実行するには、SDLチェック設定を変更しておく必要があります。
1.プロジェクト名を右クリックして、「プロパティ」をクリックします。
2.「C/C++」→「全般」→「SDLチェック」を「いいえ」に切り替えて「OK」をクリックします。

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    FILE* fp;
    char buf[64];

    // 書き込み専用でオープン
    fp = fopen("sample.txt", "w");
    if (fp == NULL) {
        exit(1);
    }

    fputs("Learning C language\nis fun and practical\nstep by step", fp);
    fclose(fp);

    // 読み取り専用でオープン
    fp = fopen("sample.txt", "r");
    if (fp == NULL) {
        exit(1);
    }

    while (fgets(buf, 64, fp) != NULL) {
        printf("%s", buf);
    }

    printf("\n");
    fclose(fp);

    return 0;
}

fputs ― 文字列をまとめて書き込む

書式

int fputs(const char* dest, FILE* fp)

引数と戻り値

項目内容
dest書き込む文字列
fp書き込み先ファイルのファイルポインタ
戻り値正常時は0、失敗時は EOF

fputs の動作

fputs は、

  • ヌル文字で終わる文字列を受け取り
  • ヌル文字の直前までを
  • まとめてファイルへ書き込む

という関数です。

ポイントは、
ヌル文字そのものは書き込まれない という点です。

そのため、文字列の途中にヌル文字が含まれている場合、
そこまでしか書き込まれません。

fgets ― ファイルから1行を読み取る

書式

char* fgets(char* dest, int maxlen, FILE* fp)

引数と戻り値

項目内容
dest読み取った文字列を格納する配列
maxlen読み取る最大バイト数
fp読み取り元ファイルのファイルポインタ
戻り値dest、終端または失敗時は NULL

fgets の動作

fgets は、次のいずれかまでを読み取ります。

  • 改行文字が現れたところまで
  • ファイルの終端まで
  • 指定した最大サイズの手前まで

読み取った結果は、必ず

  • 改行文字(存在すれば)
  • ヌル文字

を含む形で配列に格納されます。

改行文字とヌル文字の扱い

fgets を使うときに特に重要なのが、
改行文字とヌル文字の扱い です。

状況配列に格納される内容
改行がある文字列 + 改行文字 + ヌル文字
改行がない文字列 + ヌル文字

つまり、
改行文字も文字列の一部として扱われる点に注意が必要です。

そのため、表示や文字列処理を行う際に、
改行を除去したい場合は追加処理が必要になることもあります。

第2引数 maxlen の重要性

fgets の第2引数は、
読み取ってよい最大バイト数 を指定します。

これは、安全のために非常に重要です。

もしファイルに、

  • 改行がまったく存在しない。
  • 非常に長い1行が続く。

といったデータがあった場合、
制限なしで読み取ると、
配列のサイズを超えて書き込んでしまう危険があります。

fgets は、

  • 最大 maxlen - 1 文字まで読み取り。
  • 最後に必ずヌル文字を付加する。

という動作をすることで、
バッファオーバーフローを防いでいます。

fputs と fgets の特徴まとめ

メリット

項目内容
処理が簡潔ループ回数が減る。
可読性が高いコードがわかりやすい。
安全性fgets は最大サイズを指定できる。

注意点

項目内容
改行文字fgets は改行も読み取る。
ヌル文字fputs はヌル文字までしか書かない。
サイズ管理バッファサイズを意識する必要がある。

ここまでのまとめ

この節で押さえておきたいポイントは次のとおりです。

  • fputs は文字列をまとめて書き込む。
  • fgets は1行単位で安全に読み取れる。
  • 改行文字とヌル文字の扱いを理解する。
  • fgets の第2引数は必ず指定する。

1文字単位の入出力を理解した上で、
文字列単位の関数を使えるようになると、
C言語のファイル操作が一気に楽になります。

この内容を理解できれば、
テキストファイルの読み書きはもう怖くありません 👍