C言語入門|1文字単位のファイル入出力:fputcとfgetc

いよいよ“読む・書く”に踏み込む

よし、ファイルを開いて閉じるところまではできました!
次はいよいよ ファイルに書き込む、そして ファイルから読み取る 処理です。

C言語には、データをどのくらいの単位で扱うかに応じて、
さまざまな入出力関数が用意されています。

まずは一番シンプルで基本となる
1文字単位の読み書き から体験していきましょう。

C言語における「1文字」とは

ここでいう「1文字」とは、
1バイト分のデータ を意味します。

C言語では、伝統的に

  • 1文字 = 1バイト
  • ASCIIコードで表現できる文字

という前提で文字を扱います。

そのため、1文字単位のファイル入出力は
1バイト単位の入出力 と言い換えることもできます。

fputc と fgetc の役割

1文字単位のファイル入出力を行う基本関数が、次の2つです。

関数名役割
fputcファイルに1文字書き込む。
fgetcファイルから1文字読み取る。

どちらも stdio.h に定義されている、
とても歴史のある関数です。

1文字ずつ書いて、1文字ずつ読む例

次のプログラムは、

  1. 文字列を1文字ずつファイルに書き込み
  2. そのファイルを1文字ずつ読み取って
  3. 画面に表示する

という処理を行います。

サンプルプログラム

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

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

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

int main(void)
{
    FILE* fp;
    char text[] = "FileIO";   // 書き込む文字列
    int len = strlen(text);
    int ch;

    // 書き込み専用でファイルを開く
    fp = fopen("sample.txt", "w");
    if (fp == NULL) {
        exit(1);
    }

    for (int i = 0; i < len; i++) {
        fputc(text[i], fp);   // 1文字ずつ書き込む
    }

    fclose(fp);

    // 読み取り専用でファイルを開く
    fp = fopen("sample.txt", "r");
    if (fp == NULL) {
        exit(1);
    }

    while ((ch = fgetc(fp)) != EOF) {
        printf("%c", ch);     // 1文字ずつ表示
    }

    printf("\n");

    fclose(fp);
    return 0;
}

fputc ― 1文字を書き込む

書式

int fputc(int ch, FILE* fp)

引数と戻り値

項目内容
ch書き込む文字(int型)
fp書き込み先ファイルのファイルポインタ
戻り値書き込んだ文字、失敗時は EOF

fputc の動作

fputc は、

  • 指定された文字を
  • ファイルポインタが指す位置に書き込み
  • 書き込み位置を自動的に次へ進める

という処理を行います。

自分で「次の位置」を指定する必要はありません。
呼び出すたびに自動で進む のがポイントです。

fgetc ― 1文字を読み取る

書式

int fgetc(FILE* fp)

引数と戻り値

項目内容
fp読み取り元ファイルのファイルポインタ
戻り値読み取った文字、終端または失敗時は EOF

fgetc の動作

fgetc は、

  • ファイルポインタが指す位置から
  • 1文字分を読み取り
  • その文字を戻り値として返す

という関数です。

読み取るたびに、
ファイル内の位置は自動的に次へ進みます。

EOF による読み取り終了判定

ファイルの終端に達すると、
fgetc は EOF を返します。

EOF は stdio.h に定義されたマクロ定数で、
その値は -1 です。

そのため、1文字ずつ読み取る場合は、
次のような形が定番になります。

while ((ch = fgetc(fp)) != EOF) {
    処理
}

これによって、

  • 読める間は処理を続け
  • ファイルの終わりでループを抜ける

という流れを自然に書けます。

なぜ戻り値は char ではなく int なのか

fputc の引数、fgetc の戻り値は
どちらも int 型 です。

これは、

  • 有効な文字(0〜255)
  • EOF(-1)

を区別する必要があるためです。

もし戻り値が char 型だと、
EOF と通常の文字を安全に区別できなくなってしまいます。

そのため、

  • 戻り値は int で受け取る。
  • EOF でないことを確認してから文字として使う。

という使い方が基本になります。

1文字単位入出力の特徴

メリット

項目内容
動作が単純仕組みがわかりやすい。
細かい制御文字単位で自由に処理できる。
基礎理解に最適ファイル操作の理解が深まる。

デメリット

項目内容
処理が遅い大量データには不向き
記述量が多いループが必要

実務では、
より大きな単位で読み書きする関数を使うことが多いですが、
この仕組みを理解しておくことがとても重要 です。

ここまでのまとめ

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

  • fputc は1文字を書き込む。
  • fgetc は1文字を読み取る。
  • 読み書き位置は自動で進む。
  • EOF を使って終端を判定する。
  • 戻り値は必ず int で受け取る。

次の記事では、
文字列単位や行単位で読み書きする関数 を紹介していきます。

ここまで理解できれば、
C言語のファイル入出力の“芯”はしっかりつかめています 👍