[C言語 標準ライブラリ] stdio.hの使い方

※本ブログでは、商品・サービスのリンク先にプロモーションを含みます。

スポンサーリンク

stdio.hは入出力の手段を実装するためのマクロ、型、関数が宣言および定義されています。

  1. マクロ
    1. _IOFBF
    2. _IOLBF
    3. _IONBF
    4. BUFSIZ
    5. EOF
    6. FILENAME_MAX
    7. FOPEN_MAX
    8. L_tmpnam
    9. NULL
    10. SEEK_CUR
    11. SEEK_END
    12. SEEK_SET
    13. TMP_MAX
    1. FILE
    2. fpos_t
    3. size_t
  2. 標準ストリーム
    1. stderr
    2. stdin
    3. stdout
  3. ファイル操作関数
    1. int remove(const char *filename)
    2. int rename(const char *old, const char *new)
    3. FILE *tmpfile(void)
    4. char *tmpnam(char *s)
  4. ファイルアクセス関数
    1. int fclose(FILE *stream)
    2. int fflush(FILE *stream)
    3. FILE *fopen(const char *filename, const char *mode)
    4. FILE *freopen(const char *filename, const char *mode, FILE *stream)
    5. void setbuf(FILE *stream, char *buf)
    6. int setvbuf(FILE *stream, char *buf, int mode, size_t size)
    7. int fprintf(FILE *stream, const char *format, …)
    8. int fscanf(FILE *stream, const char *format, …)
    9. int printf(const char *format, …)
    10. int scanf(const char *format, …)
    11. int snprintf(char * restrict s, size_t n, const char * restrict format, …)
    12. int sprintf(char *s, const char *format, …)
    13. int sscanf(const char *s, const char *format, …)
    14. int vfprintf(FILE *stream, const char *format, va_list arg)
    15. int vfscanf(FILE * restrict stream, const char * restrict format, va_list arg)
    16. int vprintf(const char *format, va_list arg)
    17. int vscanf(const char * restrict format, va_list arg)
    18. int vsnprintf(char * restrict s, size_t n, const char * restrict format, va_list arg)
    19. int vsprintf(char *s, const char *format, va_list arg)
    20. int vsscanf(const char * restrict s, const char * restrict format, va_list arg)
  5. 文字入出力関数
    1. int fgetc(FILE *stream)
    2. char *fgets(char *s, int n, FILE *stream)
    3. int fputc(int c, FILE *stream)
    4. int fputs(const char *s, FILE *stream)
    5. int getc(FILE *stream)
    6. int getchar(void)
    7. char *gets(char *s)
    8. int putc(int c, FILE *stream)
    9. int putchar(int c)
    10. int puts(const char *s)
    11. int ungetc(int c, FILE *stream)
  6. 直接入出力関数
    1. size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
    2. size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
  7. ファイル位置付け関数
    1. int fgetpos(FILE *stream, fpos_t *pos)
    2. int fseek(FILE *stream, long int offset, int whence)
    3. int fsetpos(FILE *stream, const fpos_t *pos)
    4. long int ftell(FILE *stream)
    5. void rewind(FILE *stream)
  8. エラー処理関数
    1. void clearerr(FILE *stream)
    2. int feof(FILE *stream)
    3. int ferror(FILE *stream)
    4. int perror(const char *s)
スポンサーリンク

マクロ

_IOFBF

setvbuf関数の第3引数として使用します。
入出力の完全バッファリングを行うことを指示します。

_IOLBF

setvbuf関数の第3引数として使用します。
入出力の行バッファリングを行うことを指示します。

_IONBF

setvbuf関数の第3引数として使用します。
入出力のバッファリングをしないことを指示します。

BUFSIZ

setbuf関数で使用されるバッファの大きさを示す整数です。
環境依存ですが、最低でも256が保証されます。

EOF

ファイルの終端(End Of File)を示す、int型の負の値をもつ整数です。

FILENAME_MAX

オープン可能なファイル名の最大長(char型の配列要素数)を示す整数です。(値は実装依存)

FOPEN_MAX

同時にオープン可能なファイル数を示す整数です。(値は実装依存)

L_tmpnam

tmpnam関数によって生成される一時ファイルを保持するために必要なchar型の配列要素数を示す整数です。

NULL

空(ヌル)ポインタ定数です。
locale.h、stddef.h、stdlib.h、string.h、time.h、wchar.hヘッダでも定義されています。

SEEK_CUR

fseek関数の第3引数として使用します。
シークの起点を現在のファイル位置にすることを指示します。

SEEK_END

fseek関数の第3引数として使用します。
シークの起点をファイルの終端にすることを指示します。

SEEK_SET

fseek関数の第3引数として使用します。
シークの起点をファイルの先頭にすることを指示します。

TMP_MAX

tmpnam関数によって生成されるファイルの最大数を示す整数です。(値は実装依存)

FILE

ファイル位置表示子、紐づけられたバッファへのポインタ、エラー表示子、ファイル終了表示子などのストリームを制御するために必要なすべての情報を記録することができるオブジェクト型です。

  • ファイル位置表示子(file position indicator)
    ファイル内のすべての位置を特定するために必要なすべての情報。
  • 紐づけられたバッファへのポインタ
  • エラー表示子(error indicator)
    読み取りエラーまたは書き込みエラーが起こったかどうかを記録します。
  • ファイル終了表示子(end-of-file indicator)
    ファイルの終わりに達したかどうかを記録します。

fpos_t

ファイルの中の任意の位置を指定するために、必要な全ての情報を記録することが可能なオブジェクト型です。

size_t

sizeof演算子の結果を表すための符号無し整数型です。
メモリ領域のオブジェクトサイズを表すのに適しており、配列の要素を参照する際に使用します。
stddef.h、stdlib.h、string.h、time.h、wchar.hヘッダでも定義されています。

標準ストリーム

OSのシェルで実装されている標準化された機能です。

stderr

標準エラーストリームに結び付けられた、FILEオブジェクトへのポインタです。

stdin

標準入力ストリームに結び付けられた、FILEオブジェクトへのポインタです。

stdout

標準出力ストリームに結び付けられた、FILEオブジェクトへのポインタです。

ファイル操作関数

int remove(const char *filename)

引数のfilenameで指定されたファイルを削除します。
既にファイルがオープンされている場合に、remove()を実行した場合の動作は実装依存です。
成功したときは0、失敗したときは0以外の値が返されます。

使用例:

#include <stdio.h>

int main(void)
{
    if(remove("example.txt") == 0){
        printf("ファイルの削除に成功しました。\n");
    }else{
        printf("ファイルの削除に失敗しました。\n");
    }

    return 0;
}

このコードは、”example.txt”という名前のファイルを削除しようとします。
remove関数が成功すると0を返し、その場合は”ファイルの削除に成功しました。”と表示します。
ファイルが存在しないか、あるいは何らかの理由で削除に失敗した場合、remove関数は非0の値を返し、”ファイルの削除に失敗しました。”と表示します。

int rename(const char *old, const char *new)

引数oldで指定された名前のファイル名を、引数newで指定された名前に変更します。
newで指定したファイル名が既にしていた場合の動作は実装依存です。
成功したときは0、失敗したときは0以外の値が返されます。

使用例:

#include <stdio.h>

int main(void)
{
    if(rename("old_name.txt", "new_name.txt") == 0){
        printf("ファイル名の変更に成功しました。\n");
    }else{
        printf("ファイル名の変更に失敗しました。\n");
    }

    return 0;
}

このコードは、”old_name.txt”という名前のファイルを”new_name.txt”にリネームします。
rename関数が成功すると0を返し、その場合は”ファイル名の変更に成功しました。”と表示します。
ファイルが存在しないか、あるいは何らかの理由でリネームに失敗した場合、rename関数は非0の値を返し、”ファイル名の変更に失敗しました。”と表示します。

FILE *tmpfile(void)

一時的なファイルを作成します。この関数で作成された関数はプログラムの終了時に自動的に削除されます。このためファイルをクローズする必要がありません。
ただし、プログラムが異常終了(abortなどで終了)した場合、一時ファイルが削除されるかどうかは実装依存です。
成功したときは、一時ファイルへのポインタが返され、失敗したときはNULLポインタが返されます。

使用例:

#include <stdio.h>

int main(void)
{
    FILE *tmpf = tmpfile();
    fputs("Hello World", tmpf);
    rewind(tmpf);
    char buf[12];
    fgets(buf, sizeof(buf), tmpf);
    printf("%s\n", buf);

    // ファイルは自動的に削除されますが、明示的に閉じることもできます。
    fclose(tmpf);

    return 0;
}

このコードは次の手順で動作します。

  1. tmpfile関数は一時的なファイルを作成し、そのファイルへのポインタを返します。
  2. fputs関数を使用して、そのファイルに”Hello World”と書き込みます。
  3. rewind関数を使用して、ファイルポインタをファイルの始めに戻します。
  4. fgets関数を使用して、書き込んだ文字列を読み取ります。
  5. 読み取った文字列をprintfで出力します。

なお、tmpfile関数はバイナリモードでファイルを開くため、テキストとバイナリデータの両方を書き込むことができます。

char *tmpnam(char *s)

一時ファイルとして使用可能なファイル名を生成します。
この関数は、呼ばれる度に異なるファイル名を最大でTMP_MAX回生成します。
TMP_MAX回以上呼ばれた場合の動作は実装依存です。
引数がNULLポインタの場合、内部の静的オブジェクトに結果を書き込み、そのオブジェクトへのポインタを返します。 続けて呼んだ場合、このオブジェクトは変更される場合があります。
引数がNULLポインタではない場合、少なくともL_tmpnam文字の長さを持つ配列とみなされ、この配列に結果が書き込まれ、引数を返します。
ファイル名の生成に失敗したときはNULLポインタが返されます。

使用例:

#include <stdio.h>

int main(void)
{
    char tempname[L_tmpnam];
    char *filename = tmpnam(tempname);
    
    if(filename){
        printf("生成されたテンポラリファイル名:%s\n", filename);
    }else{
        printf("テンポラリファイル名の生成に失敗しました\n");
    }

    return 0;
}

このコードは次の手順で動作します。

  1. tmpnam関数を使用して一時的なファイル名を生成します。ファイル名はtempnameという文字配列に格納されます。
  2. tmpnam関数が成功すると、filenameは一時ファイル名を指すポインタとなります。失敗すると、NULLを返します。
  3. 生成したファイル名を表示します。

注意すべきは、この関数が生成する名前は一意であると保証されていますが、その名前のファイルがすでに存在しないとは限らないということです。また、tmpnam関数はtmpnam(NULL)の形式でも呼び出すことができ、この場合は静的に確保されたバッファに一時ファイル名が書き込まれ、そのバッファへのポインタが返されます。しかし、この形式を使用すると、スレッドセーフではなくなるため注意が必要です。

さらに、tmpnam関数は一部の環境ではセキュリティ上のリスクがあるとされ、代わりにより安全なmkstempやtmpfileなどの関数が推奨されています。

スポンサーリンク

ファイルアクセス関数

int fclose(FILE *stream)

引数streamで指定されるストリームをフラッシュし、関連付けられているファイルを閉じます。
ストリームにバッファされた、書き込まれていないデータはすべてファイルに書き込まれます。
バッファされただけで、まだ読み込まれていないデータは破棄されます。
ストリームとバッファは切り離され、バッファは解放されます。
成功したときは0が返され、失敗したときはEOFが返されます。

使用例:

#include <stdio.h>

int main(void)
{
    FILE *fp = fopen("sample.txt", "r");
    if(fp == NULL){
        printf("ファイルオープンに失敗しました。\n");
        return 1;
    }

    // 何らかのファイル操作
    // ...

    if(fclose(fp) == EOF){
        printf("ファイルクローズに失敗しました。\n");
        return 1;
    }

    return 0;
}

このコードは次の手順で動作します。

  1. fopen関数を使用して、ファイル sample.txt を読み込みモードで開きます。戻り値は FILE ポインタで、これが後続のファイル操作で使用されます。ファイルのオープンに失敗すると、fopenはNULLを返します。
  2. ファイル操作(ここでは省略)を行います。
  3. fclose関数を使用してファイルを閉じます。fcloseは成功すると0を返し、エラーが発生するとEOFを返します。

int fflush(FILE *stream)

引数streamが出力ストリームまたは最新の操作が入力されていない更新ストリームを指している場合、fflush関数は、そのストリームに対する未書き込みのデータをホスト環境に配信してファイルに書き込ませます。
それ以外の場合の動作は未定義です。
streamがNULLポインタの場合、上記の動作が定義されているすべてのストリームに対してこのフラッシュ動作を実行します。
ストリームのエラーインジケータを設定し、成功した場合は0が返され、書き込みエラーが発生した場合はEOFが返されます。

使用例:

#include <stdio.h>

int main(void)
{
    FILE *fp;

    fp = fopen("test.txt", "w");
    if(fp == NULL){
        printf("ファイルのオープンに失敗しました。\n");
        return -1;
    }

    // この時点でファイルへの書き込みはバッファされている可能性がある
    fprintf(fp, "ファイルへの書き込み中...\n");
    
    // ここでバッファを強制的にフラッシュ(実際のファイルへの書き込みを強制)
    fflush(fp); 

    fprintf(fp, "ファイルに書き足す...\n");

    fclose(fp);

    return 0;
}

このコードでは、fprintf関数を使用してファイルに文字列を書き込み、その後でfflush関数を呼び出してバッファをフラッシュ(空に)します。その結果、最初のfprintfによる文字列が確実にファイルに書き込まれます。

注意点としては、fclose関数を呼び出すと、関連付けられたバッファは自動的にフラッシュされるため、通常は手動でfflushを呼び出す必要はありません。ただし、ファイルをクローズせずにデータを確実に書き込みたい場合などには、fflushを使うことがあります。

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

引数filenameが指す名前のファイルを、引数modeで指定したモードでオープンします。
modeは次のいずれかの文字列を指定します。下表以外の文字列を指定した場合の動作は未定義です。

modeに指定する文字列モードの説明
rテキストファイルの読み取りモード
wテキストファイルの書き込みモード
x書き込み用テキストファイルの作成 ※C11
aテキストファイルの追加書き込みモード
rbバイナリファイルの読み取りモード
wbバイナリファイルの書き込みモード
wbx書き込み用バイナリファイルの作成 ※C11
abバイナリファイルの追加書き込みモード
r+テキストファイルの読み取り/書き込みモード
w+テキストファイルの書き込み/読み取りモード
a+テキストファイルの読み取り/追加書き込みモード
r+b または rb+バイナリファイルの読み取り/書き込みモード
w+b または wb+バイナリファイルの書き込み/読み取りモード
w+bx または wb+xアップデート用バイナリファイルの作成 ※C11
a+b または ab+バイナリファイルの読み取り/追加書き込みモード

排他モード(最後の文字が’x’)でファイルオープンしたとき、ファイルがすでに存在するか、作成できない場合は失敗します。
成功したときはストリームを制御するオブジェクトへのポインタが返され、失敗したときはNULLポインタが返されます。

使用例:

#include <stdio.h>

int main(void)
{
    FILE *fp;
    char ch;

    fp = fopen("test.txt", "r");
    if(fp == NULL){
        printf("ファイルのオープンに失敗しました。\n");
        return -1;
    }

    while((ch = fgetc(fp)) != EOF){
        putchar(ch);
    }

    fclose(fp);

    return 0;
}

このコードでは、まずfopen関数を使用してファイルを読み込みモードで開きます。それからfgetc関数を使用してファイルから一文字ずつ読み込み、putchar関数を使用してその文字を表示します。この操作をファイルの終わり(EOF)まで行います。最後にfclose関数を使用してファイルを閉じます。

注意点としては、fopen関数を使用してファイルを開いた後は、必ずfclose関数を使用してファイルを閉じることが重要です。これは、開いたファイルがシステムリソースを占有してしまうためです。また、ファイルが開けなかった場合(例えばファイルが存在しない場合やパーミッションがない場合など)には、fopenはNULLを返すため、そのチェックも必要です。

FILE *freopen(const char *filename, const char *mode, FILE *stream)

引数filenameが指す文字列をファイル名とするファイルを開き、引数streamが指すストリームをそれに関連付けます。
引数modeはfopen関数と同様に使用されます。
filenameがNULLポインタの場合、ストリームのモードをmodeで指定されたものに変更し、現在のストリームに関連付けられているファイルの名前が使われているかのように動作します。どのようなモードの変更が許可されるか、またどのような状況下で許可されるかは実装定義です。
指定されたストリームに関連付けられているすべてのファイルを閉じます。
ファイルのクローズに失敗しても無視されます。
ストリームのエラー・インジケータとファイル終了インジケータはクリアされます。
成功したときはstreamの値が返され、失敗したときはNULLポインタが返されます。

使用例:

#include <stdio.h>

int main(void)
{
    FILE *fp;

    // 標準出力をoutput.txtにリダイレクト
    fp = freopen("output.txt", "w", stdout);
    if(fp == NULL){
        fprintf(stderr, "標準出力のリダイレクトに失敗しました。\n");
        return -1;
    }
    printf("これは、output.txtに書き込まれます。\n");

    // 標準エラー出力をerror.txtにリダイレクト
    fp = freopen("error.txt", "w", stderr);
    if(fp == NULL){
        fprintf(stderr, "標準エラー出力のリダイレクトに失敗しました。\n");
        return -1;
    }
    fprintf(stderr, "これはerror.txtに書き込まれます。\n");

    return 0;
}

このコードでは、freopen関数を使用して、標準出力をoutput.txtに、標準エラー出力をerror.txtにリダイレクトしています。その結果、それぞれの出力が指定したファイルに書き込まれます。

このコードでは、freopen関数が失敗した場合のエラーチェックも行っています。freopenが失敗した場合(例えば、指定したファイルが開けない場合など)、NULLが返されます。

ただし、一般的にはプログラムが終了すると、標準入出力ストリームは自動的にクローズされます。しかし、リダイレクトした場合でも確実にファイルをクローズするため、明示的にfclose関数を呼び出すことをお勧めします。また、標準出力や標準エラー出力を再度コンソールにリダイレクトするための汎用的な方法は存在しないため、再リダイレクトが必要な場合には別のアプローチを考慮する必要があります

void setbuf(FILE *stream, char *buf)

引数streamが指すファイルのストリームに対して、引数bufが指す配列をバッファとした、入出力用のバッファを設定します。
modeを_IOFBF, sizeをBUFSIZとしたsetvbuf関数と同じ動作です。ただし、bufがNULLポインタの場合、modeを_IONBFとしたsetvbuf関数と同じ動作です。

使用例:

#include <stdio.h>

int main(void)
{
    FILE *fp;

    fp = fopen("output.txt", "w");
    if(fp == NULL){
        perror("ファイルオープンに失敗しました。");
        return -1;
    }

    // ファイルストリームfpのバッファリングを無効にする
    setbuf(fp, NULL);

    fprintf(fp, "Hello, World!\n");
    fprintf(fp, "これはすぐに書き込む。\n");

    fclose(fp);

    return 0;
}

このコードでは、setbuf関数を使用して、ファイルストリームfpのバッファリングを無効にしています。その結果、fprintfによる出力はすぐにファイルに書き込まれます(バッファリングが無効であるため)。

通常、ファイルストリームはバッファリングが有効になっています。つまり、出力は一定のサイズのバッファに保存され、バッファが満たされるか、明示的にフラッシュされる(fflush関数の使用)、あるいはファイルが閉じられるまで、実際のファイルには書き込まれません。

しかし、場合によっては、このバッファリングを無効にすることが有用な場合があります。例えば、デバッグ出力をすぐにファイルに書き込むようにしたい場合や、多くの小さな書き込みを行うプログラムでバッファリングの遅延が許容できない場合などです。このようなケースでsetbuf関数を使用してバッファリングを無効にします。

int setvbuf(FILE *stream, char *buf, int mode, size_t size)

引数streamが指すファイルのストリームに対して、引数sizeの大きさを持った引数bufが指す配列をバッファとし、引数modeで指定したバッファリングの方法で、入出力用のバッファを設定します。
bufにNULLを指定した場合、setvbuf関数がsizeの大きさを持ったバッファを割り付けます。
modeは次のいずれかを指定します。

modeに指定する値モード説明
_IOFBF完全バッファリングバッファがいっぱいになった時点で、ホスト環境へ、またはホスト環境から文字をブロック単位で転送します。
_IOLBF行バッファリング改行文字に達した時点で、ホスト環境へ、またはホスト環境から文字をブロック単位で転送します。
_IONBFバッファリングをしない文字が入力元から、または出力先へ可能な限りすぐ現れる。

成功したときは0が返され、modeに無効な値が指定された場合、または要求に従うことができなかった場合は0以外の値が返されます。

使用例:

#include <stdio.h>

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

    fp = fopen("output.txt", "w");
    if(fp == NULL){
        perror("ファイルオープンに失敗しました。");
        return -1;
    }

    // ファイルストリームfpのバッファリングをフルバッファリングに設定し、自分のバッファを使用する
    if(setvbuf(fp, buf, _IOFBF, BUFSIZ) != 0){
        perror("バッファの設定に失敗しました。");
        return -1;
    }

    fprintf(fp, "Hello, World!\n");
    fprintf(fp, "バッファがいっぱいになったときや、ファイルが閉じられたときに書き込まれます。\n");

    fclose(fp);

    return 0;
}

このコードでは、ファイルストリームfpのバッファリングをフルバッファリングに設定し、バッファとして配列bufを使用しています。その結果、fprintfによる出力は、バッファが満たされるか、明示的にフラッシュされる(fflush関数の使用)、あるいはファイルが閉じられるまで、実際のファイルには書き込まれません。

int fprintf(FILE *stream, const char *format, …)

引数formatが指す書式文字列に従って、引数streamが指すストリームへ書き込みます。
書式文字列には、それに続く任意個数の実引数と同じ数だけの変換指定が含まれる必要があります。
書式文字列に含まれる変換指定の部分が、それに対応する後の実引数の値によって置換されます。
成功したときは書き出された文字数が返されます。出力エラーまたは表現形式エラーが発生したときは負の値が返されます。
変換指定は次のように指定します。

%[フラグ][最小フィールド幅][.][精度][長さ修飾子]変換指定子

※[]は省略可能であることを示します。

フラグ

  • ‘-‘
    変換結果をフィールド内に左詰めにします(デフォルトでは右詰)。
  • ‘+’
    符号付き変換の結果を常に正符号又は負符号で始めます(デフォルトでは負の値の場合のみ負符号で始めます)。
  • ‘ ‘ (space)
    符号付き変換の結果の最初の文字が符号でない場合、1個の空白を結果の前に付けます。
  • ‘#’
    変換指定子がoなら「0」を、xなら「0x」を、Xなら「0X」を結果の前に付加します。変換指定子がa, A, e, E, f, F, g, Gなら、小数点文字の後ろに数字が続かない場合でも、浮動小数点数の変換の結果に常に小数点文字を含めます。変換指定子がg, Gなら、後ろの続く0を結果から取り除きません。
  • ‘0’
    0を文字列の左に付加することができます。

最小フィールド幅

値を変換した結果の文字数が最小フィールド幅より少ない場合、最小フィールド幅を満たすまで左側に(-フラグがあるときは右側に)空白を詰めることです。

精度

変換指定子がd, i, u, x, Xなら、出力する数字の最小の個数を指定します。
変換指定子がa, A, e, E, f, Fなら、小数点文字の後ろに出力すべき数字の個数を指定します。
変換指定子がg, Gなら、最大の有効桁数を指定します。
変換指定子がsなら、書き込む最大のバイト数を指定します。

長さ修飾子

修飾子説明導入バージョン
hh実引数は char 型C99以降。
h実引数は short 型全バージョン。
l実引数は long 型
または wchar_t 型
または double 型
wchar_t についてはC95以降。
double についてはC99以降。
ll実引数は long long 型C99以降。
j実引数は intmax_t 型C99以降。
z実引数は size_t 型C99以降。
t実引数は ptrdiff_t 型C99以降。
L実引数は long double 型全バージョン。

変換指定子

変換指定説明
%d, %i実引数を符号付き10進表記に変換します。
%u実引数を符号無し10進表記に変換します。
%o実引数を符号無し8進表記に変換します。
%x, %X実引数を符号無し16進表記に変換します。
%xは英字abcdefを、%Xは英字ABCDEFを用います。
%f, %F実引数を小数形式の10進浮動小数点数表記に変換します。
%e, %E実引数を指数形式の10進浮動小数点数表記に変換します。
%g, %G実引数を小数形式または指数形式の10進浮動小数点数表記に変換します。
%a, %A実引数を指数形式の16進浮動小数点数表記に変換します。
%c実引数を文字に変換します。
%s実引数を文字列に変換します。
%pポインタの値に変換します。
%n整数変数に出力した文字数を格納します。
%%‘%’を出力します。

使用例:

#include <stdio.h>

int main(void)
{
    FILE *fp;

    fp = fopen("output.txt", "w");
    if(fp == NULL){
        perror("ファイルのオープンに失敗しました。");
        return -1;
    }

    int num = 100;
    const char *str = "Hello, World!";
    
    // フォーマットを指定してデータを出力
    fprintf(fp, "num = %d\n", num);
    fprintf(fp, "str = %s\n", str);

    fclose(fp);

    return 0;
}

このコードでは、変数numとstrの値をファイルに出力しています。フォーマット文字列では、%dが整数の変換指定子、%sが文字列の変換指定子として機能しています。

int fscanf(FILE *stream, const char *format, …)

引数formatが指す書式文字列に従って、streamが指すストリームから入力を、任意個数の実引数へ読み込みます。
書式文字列には、それに続く任意個数の実引数と同じ数だけの変換指定が含まれる必要があります。
ストリームからの入力が、書式文字列に含まれる変換指定に従って、それに対応する後の実引数が指す変数に代入されます。
変換が一つも行われないまま入力誤りが発生した場合、マクロEOFの値が返されます。
その他の場合、代入された入力項目の個数が返されます。
この個数は、入力中に照合誤りが発生すると、与えられた入力項目の個数より少なくなることもあり、0になることもあります。
変換指定は次のように指定します。

%[*][最大フィールド幅][長さ修飾子]変換指定子

※[]は省略可能であることを示す。

代入抑止文字です。
「*」を指定すると、入力は変換されず、読み飛ばされます。

最大フィールド幅

最大フィールド幅(文字で数えて)を指定する正の10進整数です。
入力から指定した文字数だけ変換されます。

長さ修飾子

修飾子説明導入バージョン
hh実引数は char 型C99以降。
h実引数は short 型全バージョン。
l実引数は long 型
または wchar_t 型
または double 型
wchar_t についてはC95以降。
double についてはC99以降。
ll実引数は long long 型C99以降。
j実引数は intmax_t 型C99以降。
z実引数は size_t 型C99以降。
t実引数は ptrdiff_t 型C99以降。
L実引数は long double 型全バージョン。

変換指定子

変換指定説明
%d入力を符号付き10進整数に変換します。
%i入力を符号付き整数に変換します。
%u入力を符号無し10進整数に変換します。
%o入力を符号無し8進整数に変換します。
%x入力を符号無し16進整数に変換します。
%a, %e, %f, %g入力を浮動小数点数に変換します。
%c入力を文字に変換します。
%s入力を文字列に変換します。
%p入力をポインタの値に変換します。
%n整数変数に入力した文字数を格納します。
%%1つの%と照合します。
%[走査文字の並び]走査文字の並びに含まれる文字のみを入力し、文字列に変換します。
[の直後に^を指定した場合、走査文字の並びに含まれない文字のみを入力し、文字列に変換します。

使用例:

#include <stdio.h>

int main(void)
{
    FILE *fp;

    fp = fopen("input.txt", "r");
    if(fp == NULL){
        perror("ファイルのオープンに失敗しました。");
        return -1;
    }

    int num;
    char str[100];

    // フォーマットを指定してデータを入力
    fscanf(fp, "num = %d\n", &num);
    fscanf(fp, "str = %s\n", str);

    printf("ファイルからの読み込み:num = %d, str = %s\n", num, str);

    fclose(fp);

    return 0;
}

このプログラムで使用するinput.txt:

num = 100
str = Hello,World!

このコードでは、ファイルから変数numとstrの値を入力しています。フォーマット文字列では、%dが整数のプレースホルダー、%sが文字列のプレースホルダーとして機能しています。

int printf(const char *format, …)

引数formatが指す書式文字列に従って、標準出力へ書き込みます。
stdoutを実引数として付加したfprintf関数と同等です。
成功したときは、書き出された文字数が返されます。出力エラーまたは表現形式エラーが発生したときは、負の値が返されます。

使用例:

#include <stdio.h>

int main(void)
{
    int num = 100;
    const char *str = "Hello, World!";

    // フォーマットを指定してデータを出力
    printf("num = %d\n", num);
    printf("str = %s\n", str);

    return 0;
}

実行結果:

num = 100
str = Hello, World!

int scanf(const char *format, …)

引数formatが指す書式文字列に従って、標準入力を任意個数の実引数へ読み込みます。
stdinを実引数として付加したfscanf関数と同等です。
変換が一つも行われないまま入力誤りが発生した場合、マクロEOFの値が返されます。
その他の場合、代入された入力項目の個数が返されます。この個数は、入力中に照合誤りが発生すると、与えられた入力項目の個数より少なくなることもあり、0になることもあります。

使用例:

#include <stdio.h>

int main(void)
{
    int num;
    char str[100];

    // ユーザーに入力を促す
    printf("数字を入力してください:");
    scanf("%d", &num);
    
    printf("文字列を入力してください:");
    scanf("%s", str);  // 注意: スペースは読み込まれません

    // 入力されたデータを出力
    printf("入力されたデータは、num = %d, str = %s\n", num, str);

    return 0;
}

コンソールへの入力:

100
Hello,World!

実行結果:

入力されたデータは、num = 100, str = Hello,World!

int snprintf(char * restrict s, size_t n, const char * restrict format, …)

引数formatが指す書式文字列に従って、nで指定した書き込む文字数分だけ、sが指す配列へ書き込みます。
生成された出力をストリームではなく実引数sで指定する配列に書き込むことを除いては、fprintf関数と同等です。
書き込む文字数にはNULL文字を含みます。
領域の重なり合うオブジェクト間でコピーが行われるとき、その動作は未定義です。
成功したときは、nが十分に大きい場合に配列に書き込んだはずの文字数が返されます。
ただし、終端NULL文字は含みません。
表現形式エラーが発生したときは、負の値が返されます。
すなわち、返却値が非負かつn未満の場合、そしてその場合に限り、NULL文字で終了している出力が完全に書き込まれています。

使用例:

#include <stdio.h>

int main(void)
{
    int num = 100;
    const char *str = "Hello, World!";
    char buffer[100];

    // フォーマットを指定してデータを文字列に書き込む
    snprintf(buffer, sizeof(buffer), "num = %d, str = %s\n", num, str);

    // 書き込んだ文字列を出力
    printf("%s", buffer);

    return 0;
}

実行結果:

num = 100, str = Hello, World!

int sprintf(char *s, const char *format, …)

引数formatが指す書式文字列に従って、sが指す配列へ書き込みます。
生成された出力をストリームではなく実引数sで指定する配列に書き込むことを除いては、fprintf関数と同等です。
書き込まれた出力文字の列の後にNULL文字を書き込みます。
領域の重なり合うオブジェクト間でコピーが行われるとき、その動作は未定義です。
成功したときは、配列に書き込まれた文字数が返されます。
ただし、NULL文字は文字数に含めません。
表現形式エラーが発生したときは、負の値が返されます。

使用例:

#include <stdio.h>

int main(void)
{
    int num = 100;
    const char *str = "Hello, World!";
    char buffer[100];

    // フォーマットを指定してデータを文字列に書き込む
    sprintf(buffer, "num = %d, str = %s\n", num, str);

    // 書き込んだ文字列を出力
    printf("%s", buffer);

    return 0;
}

実行結果:

num = 100, str = Hello, World!

int sscanf(const char *s, const char *format, …)

引数formatが指す書式文字列に従って、sが指す文字列を、任意個数の実引数へ読み込みます。
入力をストリームではなく実引数sで指定される文字列から得ることを除けば、fscanf関数と同等です。
文字列の終わりに達することが、fscanf関数でファイルの終わりに達することと同等です。
領域の重なり合うオブジェクト間でコピーが行われるとき、その動作は未定義です。
変換が一つも行われないまま入力誤りが発生した場合、マクロEOFの値が返されます。
その他の場合、代入された入力項目の個数が返されます。
この個数は、入力中に照合誤りが発生すると、与えられた入力項目の個数より少なくなることもあり、0になることもあります。

使用例:

#include <stdio.h>

int main(void)
{
    const char *str = "123 Hello,World!";
    int num;
    char buffer[50];

    // フォーマットを指定してデータを読み込む
    sscanf(str, "%d %s", &num, buffer);

    // 読み込んだデータを出力
    printf("num = %d, buffer = %s\n", num, buffer);

    return 0;
}

実行結果:

num = 123, buffer = Hello,World!

int vfprintf(FILE *stream, const char *format, va_list arg)

引数formatが指す書式文字列に従って、可変個数の実引数のリストを、streamが指すストリームへ書き込みます。
可変個数の実引数並びを、argで置き換えたfprintf関数と同等です。
vfprintf関数の呼び出し前に、va_startマクロでargを初期化する必要があります。
vfprintf関数はva_endマクロを呼び出しません。
成功したときは、書き出された文字数が返されます。
出力エラーまたは表現形式エラーが発生したときは、負の値が返されます。

使用例:

#include <stdio.h>
#include <stdarg.h>

void write_formatted(FILE *file, const char *format, ...)
{
    va_list args;

    // 引数リストを初期化
    va_start(args, format);

    // フォーマットに従ってデータをファイルに書き込む
    vfprintf(file, format, args);

    // 引数リストをクリーンアップ
    va_end(args);
}

int main(void)
{
    FILE *file = fopen("output.txt", "w");
    if(file != NULL){
        write_formatted(file, "%s, %s\n", "Hello", "World!");
        fclose(file);
    }

    return 0;
}

実行結果:(output.txtへの出力結果)

Hello, World!

int vfscanf(FILE * restrict stream, const char * restrict format, va_list arg)

引数formatが指す書式文字列に従って、streamが指すストリームから入力を、可変個数の実引数のリストへ読み込みます。
可変個数の実引数並びをargで置き換えたfscanf関数と同等です。
vfscanf関数の呼び出し前に、va_startマクロでargを初期化する必要があります。
vfscanf関数はva_endマクロを呼び出しません。
変換が一つも行われないまま入力誤りが発生した場合、マクロEOFの値が返されます。
その他の場合、代入された入力項目の個数が返されます。
この個数は、入力中に照合誤りが発生すると、与えられた入力項目の個数より少なくなることもあり、0になることもあります。

使用例:

#include <stdio.h>
#include <stdarg.h>

void read_from_file(const char* filename, const char* format, ...)
{
    FILE *file = fopen(filename, "r");
    if(file == NULL){
        perror("ファイルオープンに失敗しました。");
        return;
    }

    va_list args;
    va_start(args, format);
    vfscanf(file, format, args);
    va_end(args);

    fclose(file);
}

int main(void)
{
    int myInt;
    float myFloat;
    read_from_file("input.txt", "%d %f", &myInt, &myFloat);

    printf("読み込んだ値:%d, %f\n", myInt, myFloat);

    return 0;
}

このプログラムで使用するinput.txt:

123 45.67

実行結果:

読み込んだ値:123, 45.669998

int vprintf(const char *format, va_list arg)

引数formatが指す書式文字列に従って、可変個数の実引数のリストを、標準出力へ書き込みます。
可変個数の実引数並びをargで置き換えたprintf関数と同等です。
vprintf関数の呼び出し前に、va_startマクロでargを初期化する必要があります。
vprintf関数はva_endマクロを呼び出しません。
成功したときは、書き出された文字数が返されます。
出力エラーまたは表現形式エラーが発生したときは、負の値が返されます。

使用例:

#include <stdio.h>
#include <stdarg.h>

void error_message(const char* format, ...)
{
    va_list args;
    va_start(args, format);

    fprintf(stderr, "Error: ");
    vfprintf(stderr, format, args);
    fprintf(stderr, "\n");

    va_end(args);
}

int main(void)
{
    int error_code = 404;
    const char *error_detail = "リソースが見つかりません。";

    error_message("エラーが発生しました。エラーコード:%d、詳細:%s", error_code, error_detail);

    return 0;
}

実行結果:

Error: エラーが発生しました。エラーコード:404、詳細:リソースが見つかりません。

int vscanf(const char * restrict format, va_list arg)

引数formatが指す書式文字列に従って、標準入力を、可変個数の実引数のリストへ読み込みます。
可変個数の実引数並びをargで置き換えたscanf関数と同等です。
vscanf関数の呼び出し前に、va_startマクロでargを初期化する必要があります。
vscanf関数はva_endマクロを呼び出しません。
変換が一つも行われないまま入力誤りが発生した場合、マクロEOFの値が返されます。
その他の場合、代入された入力項目の個数が返されます。
この個数は、入力中に照合誤りが発生すると、与えられた入力項目の個数より少なくなることもあり、0になることもあります。

使用例:

#include <stdio.h>
#include <stdarg.h>

void read_from_stdin(const char* format, ...)
{
    va_list args;
    va_start(args, format);
    vscanf(format, args);
    va_end(args);
}

int main(void)
{
    int myInt;
    float myFloat;
    printf("整数と浮動小数点をスペースで区切って入力してください。: ");
    read_from_stdin("%d %f", &myInt, &myFloat);

    printf("読み込んだ値:int=%d, float=%f\n", myInt, myFloat);

    return 0;
}

コンソールへの入力:

1234 56.78

実行結果:

読み込んだ値:int=1234, float=56.779999

int vsnprintf(char * restrict s, size_t n, const char * restrict format, va_list arg)

引数formatが指す書式文字列に従って、可変個数の実引数のリストを、nで指定した書き込む文字数分だけ、sが指す配列へ書き込みます。
可変個数の実引数並びをargで置き換えたsnprintf関数と同等です。
vsnprintf関数の呼び出し前に、va_startマクロでargを初期化する必要があります。
vsnprintf関数はva_endマクロを呼び出しません。
領域の重なり合うオブジェクト間でコピーが行われるとき、その動作は未定義です。
成功したときは、nが十分に大きい場合に配列に書き込んだはずの文字数が返されます。
ただし、終端NULL文字は含みません。
表現形式エラーが発生した場合、負の値が返されます。
すなわち、返却値が非負かつn未満の場合、そしてその場合に限り、NULL文字で終了している出力が完全に書き込まれています。

使用例:

#include <stdio.h>
#include <stdarg.h>

#define MAX_ERROR_MESSAGE_SIZE 256

void generate_error_message(char* buffer, const char* format, ...)
{
    va_list args;
    va_start(args, format);

    vsnprintf(buffer, MAX_ERROR_MESSAGE_SIZE, format, args);

    va_end(args);
}

int main(void)
{
    char error_message[MAX_ERROR_MESSAGE_SIZE];

    int error_code = 404;
    const char *error_detail = "リソースが見つかりません。";

    generate_error_message(error_message, "エラーが発生しました。エラーコード:%d、詳細:%s", error_code, error_detail);

    printf("%s\n", error_message);
    return 0;
}

実行結果:

エラーが発生しました。エラーコード:404、詳細:リソースが見つかりません。

int vsprintf(char *s, const char *format, va_list arg)

引数formatが指す書式文字列に従って、可変個数の実引数のリストを、sが指す配列へ書き込みます。
可変個数の実引数並びをargで置き換えたsprintf関数と同等です。
vsprintf関数の呼び出し前に、va_startマクロでargを初期化する必要があります。
vsprintf関数はva_endマクロを呼び出しません。
領域の重なり合うオブジェクト間でコピーが行われるとき、その動作は未定義です。
成功したときは、配列に書き込まれた文字数が返されます。
ただし、NULL文字は文字数に含みません。
表現形式エラーが発生した場合、負の値が返されます。

使用例:

#include <stdio.h>
#include <stdarg.h>

#define MAX_ERROR_MESSAGE_SIZE 256

void generate_error_message(char* buffer, const char* format, ...)
{
    va_list args;
    va_start(args, format);

    vsprintf(buffer, format, args);

    va_end(args);
}

int main(void)
{
    char error_message[MAX_ERROR_MESSAGE_SIZE];

    int error_code = 404;
    const char* error_detail = "リソースが見つかりません。";

    generate_error_message(error_message, "エラーが発生しました。エラーコード:%d、詳細:%s", error_code, error_detail);

    printf("%s\n", error_message);
    return 0;
}

実行結果:

エラーが発生しました。エラーコード:404、詳細:リソースが見つかりません。

int vsscanf(const char * restrict s, const char * restrict format, va_list arg)

引数formatが指す書式文字列に従って、sが指す文字列を、可変個数の実引数のリストへ読み込みます。
可変個数の実引数並びをargで置き換えたsscanf関数と同等です。
vsscanf関数の呼び出し前に、va_startマクロでargを初期化する必要があります。
vsscanf関数はva_endマクロを呼び出しません。
変換が一つも行われないまま入力誤りが発生した場合、マクロEOFの値が返されます。
その他の場合、代入された入力項目の個数が返されます。
この個数は、入力中に照合誤りが発生すると、与えられた入力項目の個数より少なくなることもあり、0になることもあります。

使用例:

#include <stdio.h>
#include <stdarg.h>

void read_from_string(const char* str, const char* format, ...)
{
    va_list args;
    va_start(args, format);
    vsscanf(str, format, args);
    va_end(args);
}

int main(void)
{
    int myInt;
    float myFloat;
    const char *input = "123 4.56";
    read_from_string(input, "%d %f", &myInt, &myFloat);

    printf("読み込んだ値:int=%d、float=%f\n", myInt, myFloat);
    return 0;
}

実行結果:

読み込んだ値:int=123、float=4.560000
スポンサーリンク

文字入出力関数

int fgetc(FILE *stream)

引数streamが指す入力ストリームから1文字取り込み、その値が返されます。
その文字はunsigned char型として取り込まれ、そしてint型に変換され、ファイル位置表示子を進めます。
ファイル終了表示子がセットされている場合、またはファイルの終わりに達している場合、ファイル終了表示子がセットされ、EOFが返されます。
読み取りエラーが発生した場合、エラー表示子がセットされ、EOFが返されます。
その他の場合は、次の文字が返されます。

使用例:

#include <stdio.h>

int main(void)
{
    FILE *fp = fopen("input.txt", "r");
    if(fp == NULL){
        printf("ファイルオープンに失敗しました。\n");
        return 1;
    }

    int ch;
    while((ch = fgetc(fp)) != EOF){
        putchar(ch);
    }

    fclose(fp);

    return 0;
}

このプログラムで使用するinput.txt:

Hello, world!
これは、テキストファイルのサンプルです。
複数行のテキストが含まれています。

実行結果:

Hello, world!
これは、テキストファイルのサンプルです。
複数行のテキストが含まれています。

char *fgets(char *s, int n, FILE *stream)

引数streamが指すストリームから、文字の列を読み取り、sが指す配列に格納します。
読み取る文字の列は改行またはファイルの終わりまでで、読み取る文字数の最大値はn-1です。
最後にNULL文字を付けます。
成功した場合は、sが返されます。
ファイルの終わりを検出し、かつ配列に1文字も読み取っていなかった場合、または読み取りエラーが発生した場合は、NULLポインタが返されます。

使用例:

#include <stdio.h>

#define BUFFER_SIZE 256

int main(void)
{
    FILE *fp = fopen("input.txt", "r");
    if(fp == NULL){
        printf("ファイルオープンに失敗しました。\n");
        return 1;
    }

    char buffer[BUFFER_SIZE];
    while(fgets(buffer, BUFFER_SIZE, fp) != NULL){
        printf("%s", buffer);
    }

    fclose(fp);

    return 0;
}

このプログラムで使用するinput.txt:

Hello, world!
これは、テキストファイルのサンプルです。
複数行のテキストが含まれています。

実行結果:

Hello, world!
これは、テキストファイルのサンプルです。
複数行のテキストが含まれています。

int fputc(int c, FILE *stream)

引数streamが指す出力ストリームにcで指定された文字を書き込みます。
その文字は、int型からunsigned char型に変換され、ファイル位置表示子を進めます。
成功したときは、書き込んだ文字が返されます。
書き込みエラーが発生した場合は、エラー表示子がセットされ、EOFが返されます。

使用例:

#include <stdio.h>

int main(void)
{
    FILE *fp = fopen("file.txt", "w");
    if(fp == NULL){
        printf("ファイルオープンに失敗しました。\n");
        return 1;
    }

    const char *text = "Hello, world!";
    while(*text != '\0'){
        fputc(*text++, fp);
    }

    fclose(fp);

    return 0;
}

実行結果:(file.txtへの出力結果)

Hello, world!

int fputs(const char *s, FILE *stream)

引数streamが指すストリームにsが指す文字列を書き込みます。
終端NULL文字の書き込みは行いません。
書き込みエラーが発生した場合は、EOFが返されます。
その他の場合は、非負の値が返されます。

使用例:

#include <stdio.h>

int main(void)
{
    FILE *fp = fopen("file.txt", "w");
    if(fp == NULL){
        printf("ファイルオープンに失敗しました。\n");
        return 1;
    }

    const char *lines[] = {
        "Hello, world!",
        "これは、テキストファイルのサンプルです。",
        "複数行のテキストが含まれています。"
    };
    
    int num_lines = sizeof(lines) / sizeof(lines[0]);

    for(int i=0; i<num_lines; i++){
        if((fputs(lines[i], fp)==EOF) || (fputc('\n', fp)==EOF)){
            printf("ファイルへの書き込みに失敗しました。\n");
            break;
        }
    }

    fclose(fp);

    return 0;
}

実行結果:(file.txtへの出力結果)

Hello, world!
これは、テキストファイルのサンプルです。
複数行のテキストが含まれています。

int getc(FILE *stream)

引数streamが指す入力ストリームから1文字取り込み、その値が返されます。
fgetc関数と同等です。
ファイルの終わりに達している場合、ファイル終了表示子がセットされ、EOFが返されます。
読み取りエラーが発生した場合、エラー表示子がセットされ、EOFが返されます。
その他の場合は、次の文字が返されます。

使用例:

#include <stdio.h>

int main(void)
{
    FILE *fp = fopen("file.txt", "r");
    if(fp == NULL){
        printf("ファイルオープンに失敗しました。\n");
        return 1;
    }

    int ch;
    while((ch = getc(fp)) != EOF){
        putchar(ch);
    }

    fclose(fp);

    return 0;
}

このプログラムで使用するfile.txt:

Hello, world!
これは、テキストファイルのサンプルです。
複数行のテキストが含まれています。

実行結果:

Hello, world!
これは、テキストファイルのサンプルです。
複数行のテキストが含まれています。

int getchar(void)

標準入力から1文字取り込み、その値が返されます。
実引数としてstdinを指定したgetc関数と同等です。
ファイルの終わりに達している場合、ファイル終了表示子がセットされ、EOFが返されます。
読み取りエラーが発生した場合、エラー表示子がセットされ、EOFが返されます。
その他の場合は、次の文字が返されます。

使用例:

#include <stdio.h>

int main(void)
{
    printf("テキストを入力してください。Windowsの場合はCtrl+Z、Linuxの場合はCtrl+Dで停止します。\n");

    int ch;
    while((ch = getchar()) != EOF){
        putchar(ch);
    }

    return 0;
}

コマンドプロンプトへの入力:

abcdefg
Ctrl+Z

実行結果:

abcdefg

char *gets(char *s)

標準入力から文字の列を読み取り、sが指す配列に格納します。
読み取る文字の列は改行またはファイルの終わりまでです。
最後に改行文字の代わりにNULL文字を付けます。
成功した場合、sが返されます。
ファイルの終わりを検出し、かつ配列に1文字も読み取っていなかった場合、または読み取りエラーが発生した場合、NULLポインタが返されます。

使用例:

#include <stdio.h>

int main(void)
{
    char buffer[100];

    printf("文字列を入力してください。\n");
    gets(buffer);

    printf("入力された文字列:%s\n", buffer);

    return 0;
}

コマンドプロンプトに入力する文字列:

abcdef

実行結果:

abcdef

gets関数はC11で削除されました。
※gets関数は読取る文字数を指定できないため、 原理的に、バッファオーバーランを防ぐことができません。代わりにfgetsやgets_s(C11以降)のような安全な関数を使用することが推奨されます。

int putc(int c, FILE *stream)

引数streamが指す出力ストリームにcで指定された文字を書き込みます。
fputc関数と同等です。
成功したときは、書き込んだ文字が返されます。
書き込みエラーが発生したときは、エラー表示子がセットされ、EOFが返されます。

使用例:

#include <stdio.h>

int main(void)
{
    FILE *fp = fopen("file.txt", "w");
    if(fp == NULL){
        printf("ファイルオープンに失敗しました。\n");
        return 1;
    }

    const char *text = "Hello, world!";
    while(*text != '\0'){
        putc(*text++, fp);
    }

    fclose(fp);

    return 0;
}

実行結果:(file.txtへの出力結果)

Hello, world!

int putchar(int c)

標準出力にcで指定された文字を書き込みます。
第2実引数としてstdoutを指定したputc関数と同等です。
成功したときは、書き込んだ文字が返されます。
書き込みエラーが発生したときは、エラー表示子がセットされ、EOFが返されます。

使用例:

#include <stdio.h>

int main(void)
{
    const char *text = "Hello, world!";
    while(*text != '\0'){
        putchar(*text++);
    }

    return 0;
}

実行結果:

Hello, world!

int puts(const char *s)

標準出力にsが指す文字列を書き込みます。
出力の最後に改行文字を追加します。
終端NULL文字の書き込みは行いません。
書き込みエラーが発生した場合、EOFが返されます。
その他の場合、非負の値が返されます。

使用例:

#include <stdio.h>

int main(void)
{
    const char *texts[] = {"Hello, world!", "コッコ隊長の", "C言語講座!"};
    int i = 0;
    int num_of_texts = sizeof(texts) / sizeof(texts[0]);
    
    while(i < num_of_texts){
        puts(texts[i]);
        i++;
    }

    return 0;
}

実行結果:

Hello, world!
コッコ隊長の
C言語講座!

int ungetc(int c, FILE *stream)

cで指定された(unsigned charに変換された)文字を、streamが指す入力ストリームに押し戻します。
押し戻された文字は、そのストリームに対する後続の読み込みによって、押し戻された順序とは逆の順序で返されます。
ファイル位置指定関数(fseek、fsetpos、rewind)を(streamが指すストリームで)正常に呼び出した場合、そのストリームで押し戻された文字は破棄されます。
ストリームに対応する外部記憶装置は変更されません。
1文字分のプッシュバックが保証されます。
ungetc関数が同一ストリーム上で何度も呼び出され、その間にそのストリームの読み込みやファイルの位置決め操作が行われなかった場合、操作は失敗することがあります。
cの値がマクロEOFの値と等しい場合、操作は失敗し、入力ストリームは変更されません。
ungetc 関数の呼び出しに成功すると、ストリームのファイル終端インジケータがクリアされます。
テキストストリームの場合、ungetc関数の呼び出しに成功した後のファイル位置インジケータの値は、押し戻された文字がすべて読み込まれるか、または廃棄されるまで特定できません。
バイナリストリームの場合、ungetc関数の呼び出しが成功するたびに、そのファイルポジションインジケーターはデクリメントされます。
呼び出し前にその値がゼロだった場合、呼び出し後は不定です。
成功したときは、変換後に押し戻された文字が返されます。
失敗したときは、EOFが返されます。

使用例:

#include <stdio.h>

int main(void)
{
    FILE *fp = fopen("file.txt", "r");
    if(fp == NULL){
        printf("ファイルオープンに失敗しました。\n");
        return 1;
    }

    int ch;
    while((ch = fgetc(fp)) != EOF){
        if(ch == '#'){
            // コメント行が検出された場合、'#'をストリームに戻し、残りの行をスキップする。
            ungetc(ch, fp);
            char buffer[256];
            fgets(buffer, sizeof(buffer), fp);
            printf("コメント文:%s", buffer);
        }else{
            putchar(ch);
        }
    }

    fclose(fp);

    return 0;
}
Hello, world!
# この文はコメントです。
Goodbye, world!

実行結果:

Hello, world!
コメント文:# この文はコメントです。
Goodbye, world!
スポンサーリンク

直接入出力関数

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)

引数streamが指すストリームから、最大nmemb個の大きさsizeの要素を、ptrが指す配列に読み取ります。
ファイル位置表示子を読み取りに成功した文字数分進めます。
エラーが発生した場合、そのストリームのファイル位置表示子の値は不定です。
1つの要素の一部だけが読み取られた時、その値は不定です。
読み取りに成功した要素の個数が返されます。
その個数は、読み取りエラーが発生した場合、またはファイルの終わりに達した場合、nmembより小さいことがあります。

使用例:

#include <stdio.h>

int main(void)
{
    FILE *file = fopen("test.bin", "rb");
    if(file == NULL){
        perror("ファイルオープンに失敗しました。");
        return 1;
    }

    int numbers[5];
    size_t length = sizeof(numbers) / sizeof(numbers[0]);

    if(fread(numbers, sizeof(int), length, file) != length){
        perror("freadが失敗しました。");
        return 1;
    }

    for(size_t i = 0; i < length; i++){
        printf("%d ", numbers[i]);
    }
    printf("\n");

    fclose(file);

    return 0;
}

test.binの内容:

実行結果:

1 2 3 4 5

このプログラムでは、まず5つの要素を持つ整数配列 numbers を定義します。そして、fread関数でファイルからデータを読み込み、そのデータを配列に格納します。読み込むデータのサイズはsizeof(int)で、数は配列の長さであるlengthです。fread関数は読み込んだデータの数を返すため、その戻り値をチェックして全てのデータが読み込まれたことを確認します。最後に読み込んだデータを表示します。

なお、”rb”というモードでファイルを開いています。”r”は読み込みモードを意味し、”b”はバイナリモードを意味します。バイナリモードでは、データはバイトとしてそのまま読み込まれます。

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)

ptrが指す配列から,sizeで指定されたサイズのnmemb要素までをstreamが指すストリームに書き込みます。
各オブジェクトに対して、サイズコールがfputc関数に行われ、オブジェクトの上に正確に重なっているunsigned charの配列から値を(順に)取得します。
ストリームのファイル・ポジション・インジケータ(定義されている場合)は、正常に書き込まれた文字数だけ進みます。
エラーが発生した場合、ストリームのファイルポジションインジケータの結果は不定です。
書き込みに成功した要素の個数が返されます。
その個数は、書き込みエラーが発生した場合のみ、nmembよりも小さくなります。
sizeまたはnmembが0の場合は0が返され、ストリームの状態は変更されません。

使用例:

#include <stdio.h>

int main(void)
{
    FILE *file = fopen("test.bin", "wb");
    if(file == NULL){
        perror("ファイルオープンに失敗しました。");
        return 1;
    }

    int numbers[] = {1, 2, 3, 4, 5};
    size_t length = sizeof(numbers) / sizeof(numbers[0]);

    if(fwrite(numbers, sizeof(int), length, file) != length) {
        perror("fwriteが失敗しました。");
        return 1;
    }

    fclose(file);

    return 0;
}

実行結果:(text.binをバイナリエディタで表示)

このプログラムでは、まず整数配列 numbers を定義し、その長さを計算します。そして、fwrite関数でその配列をファイルに書き込んでいます。書き込むデータのサイズはsizeof(int)で、数は配列の長さであるlengthです。fwrite関数は書き込んだデータの数を返すため、その戻り値をチェックして全てのデータが書き込まれたことを確認します。

なお、”wb”というモードでファイルを開いています。”w”は書き込みモードを意味し、”b”はバイナリモードを意味します。バイナリモードでは、データはバイトとしてそのまま書き込まれます。

ファイル位置付け関数

int fgetpos(FILE *stream, fpos_t *pos)

引数streamが指すストリームの解析状態及びファイル位置表示子のその時点の値を、posが指すオブジェクトに格納します。
fsetpos関数を用いて、fgetpos関数で取得したファイル位置に、ストリームを再び位置づけることができます。
成功したときは0が返されます。
失敗したときは0以外が返され、処理系定義の正の値をerrnoに格納します。

使用例:

#include <stdio.h>

int main(void)
{
    FILE *file = fopen("test.txt", "r");
    if(file == NULL){
        perror("ファイルオープンに失敗しました。");
        return 1;
    }

    fpos_t position;
    if(fgetpos(file, &position) != 0){
        perror("fgetposが失敗しました。");
        return 1;
    }

    char buffer[100];
    if(fgets(buffer, sizeof(buffer), file) == NULL){
        perror("fgetsが失敗しました。");
        return 1;
    }

    printf("読み込み:%s", buffer);

    if(fsetpos(file, &position) != 0){
        perror("fsetposが失敗しました。");
        return 1;
    }

    if(fgets(buffer, sizeof(buffer), file) == NULL){
        perror("fgetsが失敗しました。");
        return 1;
    }

    printf("もう一度、読み込む:%s", buffer);

    fclose(file);

    return 0;
}

test.txtの内容:

Hello, world!
これは、テキストファイルのサンプルです。
複数行のテキストが含まれています。

実行結果:

読み込み:Hello, world!
もう一度、読み込む:Hello, world!

このプログラムでは、ファイルから最初の行を2回読み取って表示します。fsetpos()関数を使うことで、ファイルの任意の位置にシークすることが可能です。

int fseek(FILE *stream, long int offset, int whence)

引数streamが指すストリームのファイル位置表示子の値を変更します。
読み取りエラーまたは書き込みエラーが発生した場合、エラー表示子がセットされ、fseek関数は失敗します。
バイナリストリームの場合、新しい位置は、whenceが指す位置にoffsetを加えた位置です。
whenceにはSEEK_SET, SEEK_CUR, SEEK_ENDのいずれかを指定し、SEEK_SETはファイルの初め、SEEK_CURはファイル位置表示子のその時点の値、SEEK_ENDはファイルの終わりを意味します。
SEEK_ENDを指定した場合、呼び出しが意味のあるものとしてサポートされるとは限りません。
テキストストリームの場合、offsetに0を指定する、または同じファイルに結び付けられたストリームに対する以前の成功したftell関数の呼び出しで返された値を指定する必要があります。
後者の場合whenceにはSEEK_SETを指定します。
fseek関数の呼び出しに成功すると、新しい位置を決定した後、ストリームに対するungetc関数の効果をすべて解除し、そのストリームのファイル終了表示子をクリアした上で、ファイル位置表示子を新しい位置に設定します。
fseek関数の呼び出しが成功した後では、更新ストリームに対する次の操作は入力でも出力でもよい。
要求を満足できなかった場合に限り、0以外の値が返されます。

使用例:

#include <stdio.h>

int main(void)
{
    FILE *file = fopen("test.txt", "r");
    if(file == NULL){
        perror("ファイルオープンに失敗しました。");
        return 1;
    }

    if(fseek(file, 10, SEEK_SET) != 0){
        perror("fseekが失敗しました。");
        return 1;
    }

    char buffer[100];
    if(fgets(buffer, sizeof(buffer), file) == NULL){
        perror("fgetsが失敗しました。");
        return 1;
    }

    printf("読み込み:%s", buffer);

    fclose(file);

    return 0;
}

test.txtの内容:

Hello, world!
これは、テキストファイルのサンプルです。
複数行のテキストが含まれています。

実行結果:

読み込み:ld!

int fsetpos(FILE *stream, const fpos_t *pos)

posが指すオブジェクトの値に従って、streamが指すストリームのmbstate_tオブジェクトおよびファイル位置表示子を設定します。
fsetpos関数を用いて、fgetpos関数で取得したファイル位置に、ストリームを再び位置づけることができます。
読み取りエラーまたは書き込みエラーが発生した場合、そのストリームに対するエラー表示子が設定され、fsetposは失敗します。
fsetpos関数の呼び出しに成功すると、そのストリームに対するungetc関数の効果をすべて解除し、そのストリームのファイル終了表示子をクリアしたうえで、新しい解析状態を設定し、ファイル位置表示子を新しい位置に設定します。
fsetposの呼び出しが成功した後では、更新ストリームに対する次の操作は入力でも出力でもよい。
成功したとき、0が返されます。
失敗したとき、0以外の値が返され、処理系定義の正の値をerrnoに格納します。

使用例:

#include <stdio.h>

int main(void)
{
    FILE *file = fopen("test.txt", "r");
    if(file == NULL){
        perror("ファイルオープンに失敗しました。");
        return 1;
    }

    fpos_t position;
    if(fgetpos(file, &position) != 0){
        perror("fgetposが失敗しました。");
        return 1;
    }

    char buffer[100];
    if(fgets(buffer, sizeof(buffer), file) == NULL){
        perror("fgetsが失敗しました。");
        return 1;
    }

    printf("読み込み:%s", buffer);

    if(fsetpos(file, &position) != 0){
        perror("fsetposが失敗しました。");
        return 1;
    }

    if(fgets(buffer, sizeof(buffer), file) == NULL){
        perror("fgetsが失敗しました。");
        return 1;
    }

    printf("もう一度、読み込む:%s", buffer);

    fclose(file);

    return 0;
}

test.txtの内容:

Hello, world!
これは、テキストファイルのサンプルです。
複数行のテキストが含まれています。

実行結果:

読み込み:Hello, world!
もう一度、読み込む:Hello, world!

このプログラムでは、ファイルから最初の行を2回読み取って表示します。fsetpos()関数を使うことで、ファイルの任意の位置にシークすることが可能です。

long int ftell(FILE *stream)

引数streamが指すストリームのファイル位置表示子のその時点の値を得ます。
バイナリストリームの場合、その値はファイルの始めからの文字数です。
テキストストリームの場合、そのファイル位置表示子は、ftell関数の呼び出し時の位置にそのストリームのファイル位置表示子を戻すために、fseek関数で使用できる情報を含みます。
ただし、この情報の内容は未規定です。
ftell関数の2回の呼び出し戻り値の差は、書き込み文字数または読み取り文字数という意味を持つとは限りません。
成功したとき、そのストリームのファイル位置表示子のその時点の値が返されます。
失敗したとき、-1Lが返され、処理系定義の正の値をerrnoに格納します。

使用例:

#include <stdio.h>

int main(void)
{
    FILE *file = fopen("test.txt", "r");
    if(file == NULL){
        perror("ファイルオープンに失敗しました。");
        return 1;
    }

    int c;
    while((c = fgetc(file)) != EOF){
        putchar(c);
        if(c == '\n'){
            long position = ftell(file);
            printf("現在のファイル位置:%ld\n", position);
        }
    }

    fclose(file);

    return 0;
}

test.txtの内容:

Hello, world!
これは、テキストファイルのサンプルです。
複数行のテキストが含まれています。

実行結果:

Hello, world!
現在のファイル位置:13
これは、テキストファイルのサンプルです。
現在のファイル位置:55
複数行のテキストが含まれています。

このプログラムでは、fgetc関数を使ってファイルから文字を一つずつ読み取り、それを表示しています。改行文字を読み取った後にftell関数を呼び出して、現在のファイル位置を取得し表示します。これにより、それぞれの行がファイルのどの位置で終わっているかを知ることができます。

void rewind(FILE *stream)

引数streamが指すストリームに対応するファイル位置表示子を、そのファイルの始めに位置付けます。
すなわち、そのストリームに対応するエラー表示子をクリアすることを除けば、

(void)fseek(stream, 0L, SEEK_SET)

と同等です。

使用例:

#include <stdio.h>

int main(void)
{
    FILE *file = fopen("test.txt", "r");
    if(file == NULL){
        perror("ファイルオープンに失敗しました。");
        return 1;
    }

    // ファイルの内容を表示(1回目)
    int c;
    while((c = fgetc(file)) != EOF){
        putchar(c);
    }

    // ファイルポインタを開始位置に戻す
    rewind(file);

    printf("\n");

    // ファイルの内容を表示(2回目)
    while((c = fgetc(file)) != EOF){
        putchar(c);
    }

    fclose(file);

    return 0;
}

test.txtの内容:

Hello, world!

実行結果:

Hello, world!
Hello, world!

エラー処理関数

void clearerr(FILE *stream)

引数streamが指すストリームのファイル終了表示子およびエラー表示子をクリアします。

使用例:

#include <stdio.h>

int main(void)
{
    FILE *file = fopen("test.txt", "r");
    if(file == NULL){
        perror("ファイルオープンに失敗しました。");
        return 1;
    }

    int c;
    while((c = fgetc(file)) != EOF){
        putchar(c);
    }

    if(feof(file)){
        printf("\nファイルの終端に到達しました。\n");
    }else if(ferror(file)){
        perror("ファイルの読み込みエラー。");
    }

    clearerr(file);

    if(!feof(file) && !ferror(file)){
        printf("エラーフラグとEOFフラグがクリアされています。\n");
    }

    fclose(file);

    return 0;
}

test.txtの内容:

Hello, world!

実行結果:

Hello, world!
ファイルの終端に到達しました。
エラーフラグとEOFフラグがクリアされています。

int feof(FILE *stream)

引数streamが指すストリームのファイル終了表示子を判定します。
streamのファイル終了表示子がセットされている場合、0以外の値が返されます。
セットされていない場合、0が返されます。

使用例:

#include <stdio.h>

int main(void)
{
    FILE *file = fopen("test.txt", "r");
    if(file == NULL){
        perror("ファイルオープンに失敗しました。");
        return 1;
    }

    int c;
    while((c = fgetc(file)) != EOF){
        putchar(c);
    }

    if(feof(file)){
        printf("\nファイルの終端に到達しました。\n");
    }else if(ferror(file)){
        perror("ファイルの読み込みエラー。");
    }

    fclose(file);

    return 0;
}

test.txtの内容:

Hello, world!

実行結果:

Hello, world!
ファイルの終端に到達しました。

int ferror(FILE *stream)

引数streamが指すストリームのエラー表示子を判定します。
streamのエラー表示子がセットされている場合、0以外の値が返されます。
セットされていない場合、0が返されます。

使用例:

#include <stdio.h>

int main(void)
{
    FILE *file = fopen("test.txt", "r");

    if(file == NULL){
        perror("ファイルオープンに失敗しました。");
        return 1;
    }

    const char *str = "Hello, World!\n";
    size_t len = fwrite(str, sizeof(char), sizeof(str), file);

    if(ferror(file)){
        perror("ファイルへの書き込みエラー。");
        return 1;
    }

    fclose(file);

    return 0;
}

実行結果:

ファイルへの書き込みエラー。: Bad file descriptor

上記のプログラムは、fwrite関数でファイルに書き込みを試みます。書き込み操作でエラーが発生した場合、ferror関数は非ゼロ値を返し、その後perror関数がエラーメッセージをstderrに出力します。
注意:fwrite関数がエラーを返すとは限らないため、エラーチェックにはferror関数を使用することが重要です。

int perror(const char *s)

整数式errnoのエラー番号に対応するエラーメッセージを生成します。
すなわち標準エラーストリームに文字の並びを書き込みます。
その文字の並びは、sがNULLポインタでなく、かつsが指す文字がNULL文字でないなら、

{ 仮引数 s の内容 }: エラーメッセージ

であり、それ以外なら、

エラーメッセージ

です。
errnoは静的な場所に格納されるエラーコードによってエラー状態を報告するマクロです。
ヘッダー(errno.h)で定義されています。

使用例:

#include <stdio.h>

int main(void)
{
    FILE *file = fopen("non_existent_file.txt", "r");
    if(file == NULL){
        perror("エラーが発生しました。");
        return 1;
    }

    // ファイルを使用する何らかの処理...

    fclose(file);

    return 0;
}

実行結果:

エラーが発生しました。: No such file or directory
スポンサーリンク
C言語
コッコ隊長の勉強部屋

コメント