06 ファイルアクセス(構造体入門・FILE・fopen)

プログラムが扱うデータは、実行が終わると消えてしまう。データをファイルに書き出せば、次に起動したときも読み戻せる。C言語ではファイルを FILE という構造体へのポインタで扱い、fopen で開いて読み書きし、fclose で閉じる。2級ではこの一連の流れと、'¥0'EOFNULL の区別がよく問われる。

✅ この章のゴール:① 構造体 struct が「異なる型をひとまとめにする箱」だと説明できる ② FILE *fp;fopen のモード r/w/a・失敗時 NULL が分かる ③ fputc(書き込み)/fgetc(読み込み)/EOF/fclose で1文字ずつ読み書きできる。

06-1 構造体とは

ファイルの話の前に「構造体」を少しだけ。ここではざっくり理解して、ファイルアクセスへ進んでほしい。

構造体(struct)は、異なる型のデータをひとまとまりにして扱うデータ構造である。配列が「同じ型を並べる箱」だったのに対し、構造体は「種類の違うデータを1つにまとめる箱」だと考えるとよい。C言語では struct キーワードを使って定義する。

構造体の定義

struct FileData {
    char filename[50];   /* 文字列(char 配列)*/
    int  size;           /* 整数 */
};

この例では、filename(文字列)と size(整数)という異なる型を持つ FileData という構造体を定義している。

構造体の使用例

struct FileData file = {"example.txt", 1024};
printf("ファイル名: %s, サイズ: %d¥n", file.filename, file.size);

中身の各メンバには file.filenamefile.size のように ドット . でアクセスする。

⚠ C言語では、ファイル入出力を扱うための構造体 FILE が標準ライブラリ <stdio.h> であらかじめ定義されている。私たちが FILE の中身を直接いじることはほとんどなく、その「アドレス(ポインタ)」を fopen から受け取って使うだけでよい。
構造体はクラスの元になった概念。構造体は、オブジェクト指向言語(C++ など)におけるクラス(class)の元となる概念である。C++ では struct にメソッド(関数)を持たせることで、クラスと同様に扱える。「C++ のクラスを習うと、その正体は構造体の進化形だった」とつながる。

06-2 ファイル入出力とは(本棚のたとえ)

C言語では、標準ライブラリを利用してファイルの読み書きを行うことができる。これは、私たちが本棚から本を取り出す → 開く → 読み書きする → 閉じる → 本棚へしまう、という動作とよく似ている。

本棚のイメージC言語の関数
本を取り出して開くfopen()(ファイルを開く)
本に書き込むfputc() など(書き込み)
本を読むfgetc() など(読み込み)
本を閉じて棚へしまうfclose()(ファイルを閉じる)

主に fopen() 関数でファイルを開き、fclose() 関数で閉じる。開いたら必ず閉じるのが基本である。


06-3 FILE 構造体とポインタ

ファイル操作には、FILE 構造体へのポインタを使用する。

FILE *fp;

このポインタは fopen() によって取得し、以降のファイル操作(読み書き・クローズ)すべてで「どのファイルか」を表す合言葉として使う。

FILE *fp;* は「FILE 構造体を指すポインタ」という意味。fp 自体はファイルの実体ではなく、ファイルの場所を指す“しおり”のようなものだと考えるとよい。

06-4 fopen() 関数(ファイルを開く)

fopen() 関数はファイルを開くために使用され、成功すると FILE 型のポインタを返す

書式

FILE *fopen(const char *filename, const char *mode);

使用例

FILE *fp;

fp = fopen("example.txt", "r");
if (fp == NULL) {
    printf("ファイルを開けません¥n");
    return 1;
}

fopen() のモード一覧

モード意味説明
"r"読み込み(read)ファイルが存在しない場合はエラー(NULL
"w"書き込み(write)新規作成または上書き(既存の中身は消える)
"a"追記(append)末尾に追加。ファイルがなければ新規作成
"w"「新規作成または上書き」。既にあるファイルを "w" で開くと、元の中身は消える点に注意。中身を残して足したいときは "a"(追記)を使う。
開けたか必ず確認するfopen は失敗すると NULL を返す(存在しないファイルを "r" で開いた、権限がない 等)。直後に if (fp == NULL) でチェックしてから読み書きするのが鉄則。チェックせず NULL のまま使うと暴走する。

06-5 fclose() 関数(ファイルを閉じる)

fclose() 関数は、開いたファイルを閉じる。

int fclose(FILE *fp);

使用例

fclose(fp);
⚠ 閉じ忘れると、書き込んだ内容がファイルに反映されないまま残ったり(バッファに溜まったまま)、ファイルが開きっぱなしになったりする。開いたら閉じるをセットで覚える。

06-6 fputc() 関数(1文字の書き込み)

fputc() は、1文字をファイルに書き込む関数である。ファイルへ c(char:文字)を put(置く) と考えるとよい。

int fputc(int c, FILE *fp);

使用例

#include <stdio.h>

int main(void)
{
    FILE *fp;

    fp = fopen("output.txt", "w");   /* 書き込みモードで開く */
    if (fp == NULL) {
        printf("ファイルを開けません¥n");
        return 1;
    }

    fputc('A', fp);   /* 1文字 'A' を output.txt に書き込む */

    fclose(fp);
    return 0;
}

このプログラムを実行すると、output.txt の中身は A の1文字だけになる。


06-7 fgetc() 関数(1文字の読み込み)と EOF

fgetc() は、1文字をファイルから読み取る関数である。ファイルから c(char:文字)を get(得る) と考えるとよい。

int fgetc(FILE *fp);
受け取る変数は char ではなく intfgetc は読み取った文字に加えて、ファイルの終わりを示す EOF(負の値、ふつう -1)も返すことがある。char で受けると EOF と区別できず、読み取り終了を正しく判定できない。だから戻り値は int 型で受ける。

EOF(End of File)

ファイルの終端を示す特殊な値 EOF は、ファイル読み取りの終了を判定するために使う。「もう読む文字がない」という合図である。

ファイルを最後まで1文字ずつ読む(典型パターン)

#include <stdio.h>

int main(void)
{
    FILE *fp;
    int  c;   /* fgetc の戻り値を受けるので int(EOF と比較するため)*/

    fp = fopen("example.txt", "r");
    if (fp == NULL) {
        printf("ファイルを開けません¥n");
        return 1;
    }

    while ((c = fgetc(fp)) != EOF) {   /* EOF が来るまで1文字ずつ */
        printf("%c", c);               /* 読んだ文字を画面に表示 */
    }

    fclose(fp);
    return 0;
}
while ((c = fgetc(fp)) != EOF) は「1文字読んで c に入れ、それが EOF でない間くり返す」という超頻出パターン。cint で宣言するのは EOF と正しく比べるため。

06-8 NULL ポインタ

fopen() が失敗した場合は NULL を返す。NULL は「どこも指していない」ことを表す特別なポインタの値である。

FILE *fp;

fp = fopen("nonexistent.txt", "r");   /* 存在しないファイルを読み込みで開こうとする */
if (fp == NULL) {
    printf("ファイルが開けません¥n");
}
紛らわしい3つを区別する(2級頻出):
'¥0'(ヌル文字)=文字列の終わり
EOFファイル(入力)の終わり
NULLどこも指さないポインタfopen 失敗時の戻り値)

06-9 📝 過去問で確認

過去問(第59回 問2 ファイル処理)— まず自分で解いてみよう
第59回 問2 ファイル処理 問題①
第59回 問2 問題 ①
第59回 問2 ファイル処理 問題②
問題 ②
解説を表示
第59回 問2 ファイル処理 解説
解説
過去問(ファイルアクセス)— まず自分で解いてみよう
ファイルアクセスの過去問 問題
問題
解説を表示
ファイルアクセスの過去問 解説
解説

06-10 まとめ


06-11 理解度チェック

Q1. fopen() がファイルを開くのに失敗したとき返す値はどれか。

解説を表示

正解:ウ(NULL)

fopen は成功すると FILE へのポインタを、失敗すると NULL を返す。開いた直後に if (fp == NULL) で確認するのが鉄則。EOF はファイルの終わりを示す別物。

Q2. fopen のモード "w" の意味として正しいものはどれか。

解説を表示

正解:イ(書き込み・新規作成または上書き)

"w"=write。既存ファイルを開くと元の中身は消えて上書きされる。中身を残して足すなら "a"(追記)、読み込みは "r"

Q3. fgetc() の戻り値を受け取る変数の型として適切なものはどれか。

解説を表示

正解:エ(int)

fgetc は読んだ文字のほかに、ファイルの終わりを示す EOF(負の値)も返す。char で受けると EOF と区別できず終了判定を誤るため、int で受ける。だから while ((c = fgetc(fp)) != EOF)cint

Q4. 特殊な値 EOF が示すものはどれか。

解説を表示

正解:イ(ファイルの終わり)

EOF=End Of File。「もう読む文字がない」という合図で、読み取り終了の判定に使う。文字列の終わりは '¥0'、どこも指さないポインタは NULL

Q5. fputc('A', fp) の動作として正しいものはどれか。

解説を表示

正解:ア(1文字 'A' を書き込む)

fputc=ファイルへ char を put(置く)。第1引数の1文字を、第2引数 fp が指すファイルに書き込む。読み込みは fgetc、閉じるのは fclose

Q6. fclose(fp) の役割はどれか。

解説を表示

正解:ウ(開いたファイルを閉じる)

fclosefopen で開いたファイルを閉じる。閉じ忘れると書き込み内容が反映されないことがある。開いたら閉じるをセットで覚える。

Q7. 構造体(struct)の説明として最も適切なものはどれか。

解説を表示

正解:エ(異なる型をまとめる箱)

配列が「同じ型を並べる」のに対し、構造体は char filename[50];int size; のように異なる型をひとまとめにできる。FILE も構造体で、C++ のクラスの元になった概念。