閉じる

C言語のstdin stdout stderrとは? 役割と基本の読み書き

C言語ではプログラムが外の世界とやり取りするために、標準入力(stdin)、標準出力(stdout)、標準エラー出力(stderr)という3つのストリームが最初から用意されています。

これらの役割と基本的な使い方を理解することは、入門の大きな一歩です。

本記事では、初心者の方にも分かるように、読み書きの基本とバッファ、リダイレクトまで丁寧に解説します。

stdin stdout stderrの基本

標準ストリームは、ヘッダstdio.hで定義されている3つのFILE*ポインタです。

通常は次のように端末(TTY)に接続されていますが、リダイレクトするとファイルやパイプなどに切り替わります。

標準入力(stdin)とは

標準入力(stdin)は、プログラムが外部からデータを受け取る入り口です。

キーボード入力やファイル、パイプからデータを読み込みます。

型はFILE*で、識別子はstdinです。

代表的な用途

ユーザーに数値や文字列の入力を求めたり、別プログラムの出力をパイプで受け取るときに使います。

関数としてはscanfgetcharfgetsなどが使われます。

初心者が押さえるポイント

入力関数の戻り値を必ず確認しましょう。

失敗したまま進むと未定義の動作を招きやすいです。

標準出力(stdout)とは

標準出力(stdout)は、プログラムの通常の結果を表示する出口です。

型はFILE*で、識別子はstdoutです。

代表的な用途

計算結果やメッセージを画面に表示する、あるいはリダイレクトでファイルに書き出す用途に使います。

関数はprintfputsputcharなどです。

標準エラー出力(stderr)とは

標準エラー出力(stderr)は、エラーや警告などのメッセージ専用の出口です。

型はFILE*で、識別子はstderrです。

代表的な用途

入力エラー、ファイルオープン失敗、使い方の誤りなどの通知に使います。

fprintf(stderr, ...)perrorがよく使われます。

stdoutとstderrの違い

  • 目的の違い: stdoutは通常の結果、stderrはエラー通知に使います。
  • リダイレクトの独立性: stdoutをファイルにリダイレクトしても、stderrはデフォルトでは別扱いです。結果とエラーを別ファイルに分けられます。
  • バッファリングの違い: 多くの実装では、端末接続時のstdoutは行バッファリングstderrは無バッファ(すぐ表示)です。ファイルにリダイレクトされるとstdoutは全バッファ、stderrは行バッファや無バッファになることがあります。

次の表に3ストリームの要点をまとめます。

ストリーム識別子方向典型的な接続先主な関数既定のバッファリング(典型)
標準入力stdin入力キーボード、ファイル、パイプscanfgetcharfgets行バッファ/全バッファ
標準出力stdout出力画面、ファイル、パイプprintfputsputchar行バッファ(端末)または全バッファ(ファイル)
標準エラーstderr出力画面fprintfperror無バッファまたは行バッファ
注意

バッファリングは実装や環境で異なる場合があります。

絶対にこうなる、と決め打ちしないことが重要です。

stdoutに出力する基本

printfでstdoutに表示

printfはフォーマット文字列に従ってstdoutへ出力します。

戻り値は出力した文字数(エラー時は負数)です。

C言語
// printf_stdout.c
#include <stdio.h>

int main(void) {
    // %d, %f, %s などのフォーマット指定で整形して表示します
    int answer = 42;
    double pi = 3.14159;
    const char *name = "C beginner";

    // \n を付けると行バッファの場合すぐ表示されやすいです
    int n = printf("Hello, %s! answer=%d, pi=%.2f\n", name, answer, pi);

    // 戻り値の確認もできます
    if (n < 0) {
        // 出力に失敗した場合
        fprintf(stderr, "printfに失敗しました\n");
        return 1;
    }
    return 0;
}
実行結果
Hello, C beginner! answer=42, pi=3.14

フォーマット指定の基本

  • %d: 整数
  • %.2f: 小数点以下2桁の浮動小数点
  • %s: 文字列
  • \n: 改行

puts/putcharの簡単出力

putsは文字列を出力して自動で改行を付けます。

putcharは1文字を出力します。

どちらもstdoutに書き込みます。

C言語
// puts_putchar.c
#include <stdio.h>

int main(void) {
    puts("1行目です");       // 末尾に自動で \n が付く
    puts("2行目も自動改行");
    putchar('A');            // 1文字出力
    putchar('\n');           // 自分で改行を付ける
    return 0;
}
実行結果
1行目です
2行目も自動改行
A

改行とバッファとfflush

バッファリングにより、出力は一時的にメモリに蓄えられてからまとめて表示されることがあります。

端末に接続されているstdoutは行バッファリングが多く、\nを出力したタイミングで表示されやすいです。

長い処理中に進捗を表示したいときはfflush(stdout)で強制的にフラッシュします。

C言語
// progress_fflush.c
#include <stdio.h>

int main(void) {
    printf("処理中");           // \n を付けていないので、環境によっては見えないことがある
    fflush(stdout);            // ここで強制的に表示

    for (int i = 0; i < 3; ++i) {
        // 時間のかかる処理のつもりで重い計算を少し回します
        volatile unsigned long x = 0;
        for (unsigned long j = 0; j < 50000000UL; ++j) {
            x += j;            // 何か計算することで最適化されにくくする
        }
        printf(".");           // 進捗をドットで表示
        fflush(stdout);        // すぐに見せたいのでフラッシュ
    }
    printf("\n完了\n");
    return 0;
}
実行結果
処理中...
完了
注意

fflush(NULL)は全出力ストリームをフラッシュします。

fflush(stdin)は未定義動作なので使用しないでください(一部処理系では拡張として動作しますが、移植性がありません)。

stdinから入力する基本

scanfで数値や文字列を読む

scanfは書式に従って標準入力から値を読み取ります。

戻り値は成功した項目数です。

失敗検出に必ず使いましょう。

C言語
// scanf_basic.c
#include <stdio.h>

int main(void) {
    int age;
    char name[100];

    printf("年齢を入力してください: ");
    if (scanf("%d", &age) != 1) {                    // 戻り値チェック
        fprintf(stderr, "年齢の読み取りに失敗しました\n");
        return 1;
    }

    printf("名前を入力してください(空白なし): ");
    if (scanf("%99s", name) != 1) {                  // 幅指定でバッファあふれ対策
        fprintf(stderr, "名前の読み取りに失敗しました\n");
        return 1;
    }

    printf("こんにちは、%sさん(%d歳)!\n", name, age);
    return 0;
}
実行結果
年齢を入力してください: 23
名前を入力してください(空白なし): Taro
こんにちは、Taroさん(23歳)!
ポイント

%sは空白で区切られます。

スペースを含む文字列を安全に読みたい場合はfgetsの利用を検討してください(本記事では扱いません)。

getcharで1文字読む

getcharは1文字をintで返します。

EOF判定のためintで受けるのが正解です。

C言語
// getchar_one.c
#include <stdio.h>

int main(void) {
    int ch;

    printf("1文字入力してください: ");
    ch = getchar();           // 1文字だけ読み取る
    if (ch == EOF) {
        fprintf(stderr, "EOFが入力されました\n");
        return 1;
    }

    printf("あなたが入力したのは '%c' です(コード: %d)\n", ch, ch);
    return 0;
}
実行結果
1文字入力してください: A
あなたが入力したのは 'A' です(コード: 65)

入力の改行と戻り値の確認

数値入力のあとにgetcharで1文字を読むと、直前の改行\nが残っていて即座に読まれてしまうことがあります。

この場合は改行を捨てる処理を入れましょう。

C言語
// consume_newline.c
#include <stdio.h>

int main(void) {
    int n;
    printf("整数を入力してください: ");
    if (scanf("%d", &n) != 1) {
        fprintf(stderr, "整数の読み取りに失敗しました\n");
        return 1;
    }

    // 改行を捨てる: scanfは末尾の改行を消費しない場合がある
    int c;
    while ((c = getchar()) != '\n' && c != EOF) {
        // 何もしない(残りを捨てる)
    }

    printf("続けますか? y/n: ");
    int ans = getchar();
    if (ans == EOF) {
        fprintf(stderr, "入力が得られませんでした\n");
        return 1;
    }

    if (ans == 'y' || ans == 'Y') {
        printf("続行します\n");
    } else {
        printf("中止します\n");
    }
    return 0;
}
実行結果
整数を入力してください: 10
続けますか? y/n: y
続行します
重要

fflush(stdin)で入力を捨てるのはNGです。

標準Cでは未定義動作なので、上のようにgetcharで読み捨てましょう。

stderrでエラー出力する基本

エラーはstderrに出す理由

エラーと正常結果を分離しておくと、ユーザーは正常な結果だけをファイルに保存し、エラーだけを画面で確認できます。

ログ収集や自動化でも扱いやすくなります。

fprintf(stderr, …)でエラー表示

fprintfで宛先にstderrを指定します。

使い方はprintfと同様です。

C言語
// use_stderr.c
#include <stdio.h>

int main(int argc, char *argv[]) {
    if (argc < 2) {
        // 使い方の誤りはstderrへ
        fprintf(stderr, "使い方: %s <ファイル名>\n", argv[0]);
        return 2; // コマンドの使い方エラーを示すコード
    }

    printf("指定されたファイル名は: %s\n", argv[1]); // 通常の情報はstdout
    return 0;
}
実行結果
$ ./use_stderr
使い方: ./use_stderr <ファイル名>          ← これはstderrに出ています
$ ./use_stderr data.txt
指定されたファイル名は: data.txt            ← これはstdoutに出ています

perrorでシステムエラーを表示

perrorは直近のシステムエラーerrnoを、分かりやすいメッセージにしてstderrへ出力します。

C言語
// perror_example.c
#include <stdio.h>

int main(void) {
    // 存在しないファイルを開いてみる
    FILE *fp = fopen("not_exist.txt", "r");
    if (fp == NULL) {
        // "fopen: No such file or directory" のように出力
        perror("fopen");  // 引数はプレフィックス。NULLでも可
        return 1;
    }
    fclose(fp);
    return 0;
}
実行結果
fopen: No such file or directory
補足

より細かく制御したい場合は#include <string.h>strerror(errno)で文字列を取り出せます。

リダイレクトでstdoutとstderrを分ける

コマンドラインのリダイレクトで、stdoutとstderrを別々のファイルへ出力できます。

Unix系シェル(Bashなど)

  • 通常出力だけを保存: ./prog > out.txt
  • エラーだけを保存: ./prog 2> err.txt
  • 両方を別々に保存: ./prog > out.txt 2> err.txt
  • 両方を1つにまとめる: ./prog > all.txt 2>&1 または ./prog 2>&1 | tee all.txt

Windows

  • CMD: prog.exe 1> out.txt 2> err.txt
  • PowerShell: .\prog.exe *> out.txt は全ストリーム。分けるなら .\prog.exe > out.txt 2> err.txt

次の小さなプログラムは、stdoutとstderrに同時に出力します。

C言語
// split_streams.c
#include <stdio.h>

int main(void) {
    printf("これはstdoutのメッセージです\n");
    fprintf(stderr, "これはstderrのメッセージです\n");
    return 0;
}
実行結果Unix系
$ ./split_streams > out.txt
これはstderrのメッセージです           ← 画面に表示(エラーはそのまま)
$ cat out.txt
これはstdoutのメッセージです
$ ./split_streams > out.txt 2> err.txt
$ cat out.txt
これはstdoutのメッセージです
$ cat err.txt
これはstderrのメッセージです

まとめ

標準入力(stdin)、標準出力(stdout)、標準エラー出力(stderr)は、プログラムの入出力の基本土台です。

stdoutは通常の結果、stderrはエラーや警告という役割分担を守ることで、リダイレクトやログ収集が扱いやすくなります。

出力時は改行とバッファの関係を意識し、必要に応じてfflush(stdout)を使って表示タイミングを制御しましょう。

入力では必ず戻り値を確認し、改行の扱いに注意することで予期しない動作を防げます。

さらに、エラー時はfprintf(stderr,...)perrorを使い分け、リダイレクトで出力を分離する実践を身につければ、堅牢で扱いやすいCプログラムを書けるようになります。

この記事を書いた人
エーテリア編集部
エーテリア編集部

プログラミングの基礎をしっかり学びたい方向けに、C言語の基本文法から解説しています。ポインタやメモリ管理も少しずつ理解できるよう工夫しています。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!