C言語の基本|C言語の標準入出力関数の基本

1文字の入口と出口を理解しよう。標準入出力関数を使い分ければ、C言語とユーザーのやり取りがもっと分かりやすくなる

C言語でプログラムを作るときに欠かせないのが、入力と出力です。

キーボードから文字や数値を受け取る処理が入力、計算結果やメッセージを画面に表示する処理が出力です。入力と出力ができるようになると、プログラムは内部で計算するだけではなく、ユーザーと情報をやり取りできるようになります。

これまでの学習でも、printfで画面に文字や数値を表示したり、scanfでキーボードから値を受け取ったりしてきたことでしょう。

C言語には、printfやscanf以外にも、次のような標準入出力関数が用意されています。

  • getcharで1文字を入力する
  • putcharで1文字を出力する
  • fgetsで1行の文字列を入力する
  • putsで文字列を出力する
  • scanfで書式に従って値を入力する
  • printfで書式に従って値を出力する

これらの関数には、それぞれ得意な処理があります。

1文字だけを扱いたい場合はgetcharやputcharが適しています。空白を含む1行の文字列を受け取りたい場合はfgetsが役立ちます。数値や文字列を指定した形式で扱いたい場合はscanfやprintfを利用できます。

大切なのは、いつも同じ関数を使うのではなく、処理するデータに合った関数を選ぶことです。

ここでは、標準入力と標準出力の考え方、getcharとputcharによる1文字の入出力、EOFによる入力終了の判定、while文を使った繰り返し入力、バッファリングの基本について順番に見ていきましょう。

標準入出力関数とは

標準入出力関数とは、プログラムがデータを受け取ったり、外部へ送り出したりするために用意されている標準ライブラリ関数です。

学習用の一般的な実行環境では、標準入力と標準出力を次のように考えられます。

種類役割一般的な接続先
標準入力プログラムへデータを渡すキーボード
標準出力プログラムからデータを送り出すディスプレイ画面

キーボードから入力されたデータは、標準入力を通ってプログラムへ渡されます。プログラムが出力したデータは、標準出力を通って画面へ送られます。

標準入力はデータの入口、標準出力はデータの出口と考えると分かりやすいでしょう。

代表的な標準入出力関数

C言語では、入力するデータや出力するデータに応じて、複数の関数を使い分けます。

関数名主な役割
getchar標準入力から1文字を読み取る
putchar標準出力へ1文字を書き込む
fgets指定した大きさの範囲で1行の文字列を読み取る
puts文字列を出力した後に改行する
scanf書式を指定して値を読み取る
printf書式を指定して文字列や値を出力する

1文字を扱うgetcharとputchar、1行の文字列を扱うfgetsとputs、書式を指定するscanfとprintfというように整理すると、それぞれの特徴をつかみやすくなります。

これらの関数を使うには、標準入出力に関する宣言などを提供するstdio.hをインクルードします。

#include <stdio.h>

stdio.hをインクルードすることで、コンパイラはgetchar、putchar、fgets、puts、scanf、printfなどの関数を正しい形式で確認できます。

図1:標準入力と標準出力の流れ

この図から分かること

キーボードから入力されたデータは、標準入力を通ってC言語のプログラムへ渡されます。プログラムが処理した結果は、標準出力を通って画面へ表示されます。

getchar、scanf、fgetsは、標準入力からデータを受け取る関数です。putchar、printf、putsは、標準出力へデータを送る関数です。

入力関数はプログラムの入口、出力関数はプログラムの出口を担当していると考えると、標準入出力の役割をイメージしやすくなります。

getchar関数とは

getcharは、標準入力から1文字を読み取る関数です。

キーボードからAを入力すると、getcharはその文字に対応する値を読み取って返します。

getcharの関数宣言は次のとおりです。

int getchar(void);

関数宣言から読み取れる内容を整理すると、次のようになります。

項目内容
戻り値の型int型
関数名getchar
引数なし
機能標準入力から1文字を読み取る
入力終了時EOFを返す
入力エラー時EOFを返す

getcharは引数を受け取りません。そのため、関数名の後ろの丸かっこには何も指定せず、次のように呼び出します。

ch = getchar();

getcharの戻り値がint型である理由

getcharは1文字を読み取る関数ですが、戻り値の型はchar型ではなくint型です。

その理由は、読み取った文字だけでなく、入力の終わりや入力エラーを表すEOFも返す必要があるためです。

getcharの戻り値には、次の2種類があります。

戻り値意味
読み取った文字の値標準入力から1文字を正常に読み取った
EOF入力の終わりに達した、または入力エラーが発生した

文字を読み取った場合、getcharはunsigned char型として扱える文字の値をint型へ変換して返します。

入力の終わりや入力エラーが発生した場合は、通常の文字と区別できる特別な値としてEOFを返します。

getcharの戻り値をchar型の変数で受け取ると、環境によっては通常の文字とEOFを正しく区別できない可能性があります。そのため、戻り値はint型の変数で受け取るのが基本です。

int ch;

ch = getchar();

chをint型にすることで、通常の文字とEOFの両方を正しく扱えます。

EOFとは

EOFはEnd Of Fileの略で、入力の終わりを表すための特別な値です。

getcharは、正常に文字を読み取った場合にはその文字の値を返します。これ以上読み取れるデータがない場合や、入力エラーが発生した場合にはEOFを返します。

EOFはstdio.hで提供されているマクロです。

EOFの値は負の整数として定義されます。多くの環境では-1ですが、プログラムの中で-1と直接比較するのではなく、EOFを使って判定します。

if (ch == EOF) {
    /* 入力の終わり、または入力エラー */
}

EOFを使えば、その値が何であるかを意識せず、入力が終了したことを分かりやすく表現できます。

putchar関数とは

putcharは、引数として受け取った1文字を標準出力へ書き込む関数です。

putcharの関数宣言は次のとおりです。

int putchar(int c);

関数宣言から読み取れる内容は次のとおりです。

項目内容
戻り値の型int型
関数名putchar
引数int型の値を1つ受け取る
機能標準出力へ1文字を書き込む
正常終了時出力した文字の値を返す
出力エラー時EOFを返す

putchar の引数が char ではなく int なのは、C言語の整数型の扱いと、標準入出力関数の設計を統一するためです。

putchar('A');

と書くと、文字 'A' は内部では文字コードに対応する整数値として扱われます。ASCII系の環境なら 'A' は 65 です。つまり、概念的には次のような処理になります。

'A'
 ↓
文字コード 65
 ↓
intとしてputcharへ渡す
 ↓
'A'を出力

画面にBを表示する場合は、次のように書きます。

putchar('B');

改行したい場合は、改行文字をputcharへ渡します。

putchar('\n');

putcharは文字列全体を出力する関数ではありません。1回の呼び出しで出力するのは1文字です。

複数の文字を出力したい場合は、putcharを複数回呼び出すか、繰り返し処理と組み合わせます。

putcharの戻り値

putcharもint型の値を返します。

文字を正常に出力できた場合は、出力した文字に対応する値を返します。出力中にエラーが発生した場合はEOFを返します。

出力結果を確認したい場合は、次のように戻り値を調べられます。

if (putchar(ch) == EOF) {
    /* 出力エラーの処理 */
}

簡単な学習用プログラムでは戻り値を使わないこともありますが、putcharにも処理結果を表す戻り値があることを覚えておきましょう。

getcharとputcharの関数宣言を読んでみよう

標準ライブラリ関数を学ぶときは、関数宣言から情報を読み取ることが大切です。

getcharの関数宣言を確認します。

int getchar(void);
宣言の要素意味
int戻り値の型
getchar関数名
void引数を受け取らない

getcharは引数を受け取らず、int型の値を返す関数です。

次に、putcharの関数宣言を確認します。

int putchar(int c);
宣言の要素意味
int戻り値の型
putchar関数名
int cint型の引数を1つ受け取る

putcharはint型の値を1つ受け取り、int型の値を返す関数です。

関数宣言を読めるようになると、関数が受け取る値と返す値を自分で確認できるようになります。

1文字を入力して表示するプログラム

getcharとputcharを使い、キーボードから入力した1文字を画面へ表示してみましょう。

入力した1文字を案内文と一緒に表示するプログラム

ファイル名:12_3_1.c

#include <stdio.h>

int main(void)
{
    int ch;

    /* 入力を案内する */
    printf("文字を1つ入力してください: ");

    /* 標準入力から1文字を読み取る */
    ch = getchar();

    /* EOFが返された場合は処理を終了する */
    if (ch == EOF) {
        printf("\n文字を読み取れませんでした。\n");
        return 1;
    }

    /* 読み取った文字を表示する */
    printf("入力した文字は ");
    putchar(ch);

    /* 改行する */
    putchar('\n');

    return 0;
}
実行結果の例

Kを入力した場合の実行結果は、次のようになります。

文字を1つ入力してください: K
入力した文字は K

1文字を入力して表示するプログラムの解説

stdio.hをインクルードする部分

#include <stdio.h>

このプログラムでは、printf、getchar、putchar、EOFを使用します。そのため、標準入出力に関する宣言やマクロを提供するstdio.hをインクルードしています。

入力した文字を受け取る変数

int ch;

getcharの戻り値を受け取るため、chをint型で宣言しています。

char型ではなくint型にすることで、通常の文字とEOFの両方を扱えます。

入力を案内する部分

printf("文字を1つ入力してください: ");

printfで、ユーザーに入力を促すメッセージを表示しています。

この文字列の末尾には改行がありません。そのため、一般的な対話型の環境では、メッセージの続きに文字を入力できます。

1文字を読み取る部分

ch = getchar();

getcharで標準入力から1文字を読み取り、その戻り値をchへ代入しています。

例えばKを入力した場合、chにはKに対応する文字コードの値が格納されます。

EOFを確認する部分

if (ch == EOF) {
    printf("\n文字を読み取れませんでした。\n");
    return 1;
}

getcharがEOFを返した場合は、通常の文字を読み取れなかったことになります。

この場合はメッセージを表示し、return 1でプログラムを終了します。

getcharの戻り値を使用する前にEOFを確認することで、入力の終わりや入力エラーを通常の文字として処理することを防げます。

入力した文字を表示する部分

printf("入力した文字は ");
putchar(ch);

printfで案内文を表示した後、putcharでchに格納されている1文字を出力します。

printfは書式付きの文字列出力を担当し、putcharは1文字の出力を担当しています。

改行する部分

putchar('\n');

putcharへ改行文字を渡し、表示位置を次の行へ移動します。

putcharは文字だけでなく、改行やタブなどの制御文字も出力できます。

正常終了を伝える部分

return 0;

return 0によってmain関数を終了し、プログラムが正常に終了したことを実行環境へ伝えます。

1文字入力で改行が残ることに注意しよう

一般的な端末でKを入力してEnterを押すと、入力されたデータにはKだけでなく、Enterによる改行も含まれます。

入力バッファの中には、次のような順番で文字が入ります。

K  \n

最初のgetcharはKを読み取ります。この時点では、改行文字が入力バッファに残っていることがあります。

続けてもう一度getcharを呼び出すと、新しい文字を入力する前に、残っている改行文字を読み取る場合があります。

getcharの呼び出し読み取る値
1回目K
2回目改行文字
3回目次に入力された文字

getcharを複数回使うプログラムでは、Enterによる改行も1文字として読み取られることを意識しましょう。

図2:getcharとputcharによる1文字の受け渡し

この図から分かること

getcharは、標準入力から1文字を読み取り、その値をint型として返します。読み取った値をputcharへ渡すと、同じ文字を標準出力へ書き込めます。

キーボードからKを入力してEnterを押した場合、入力バッファにはKと改行文字が入ります。最初のgetcharがKだけを読み取ると、改行文字は入力バッファに残ります。

getcharは文字単位で処理するため、英字や数字だけでなく、Enterによる改行も1文字として扱う点が重要です。

入力が終わるまで1文字ずつ処理する

getcharとputcharをwhile文と組み合わせると、入力が終わるまで1文字ずつ読み取り、そのまま出力できます。

処理の基本的な流れは次のとおりです。

  • getcharで1文字を読み取る
  • 読み取った値をint型の変数へ代入する
  • 読み取った値がEOFか確認する
  • EOFでなければputcharで出力する
  • 次の文字を読み取る
  • EOFが返されたら繰り返しを終了する

この処理は、文字単位で入力をコピーする基本形になります。

1文字の入出力を繰り返すプログラム

次のプログラムは、EOFが返されるまで標準入力から1文字ずつ読み取り、その文字を標準出力へ書き込み続けます。

EOFまで入力文字を繰り返し表示するプログラム

ファイル名:12_3_2.c

#include <stdio.h>

int main(void)
{
    int ch;

    /* 入力方法を案内する */
    printf("文字列を入力してください。EOFで終了します。\n");

    /* EOFが返されるまで1文字ずつ処理する */
    while ((ch = getchar()) != EOF) {
        putchar(ch);
    }

    /* 入力の終了を表示する */
    printf("入力を終了しました。\n");

    return 0;
}
実行結果の例

Helloを入力した場合の表示例です。

文字列を入力してください。EOFで終了します。
Hello
Hello
入力を終了しました。

端末には、キーボードから入力したHelloと、putcharによって出力されたHelloの両方が表示されることがあります。

入力した文字が端末によって自動的に表示される仕組みをエコーバックといいます。そのため、実行環境によっては同じ文字列が2回表示されたように見えます。

繰り返し入力プログラムの解説

文字を受け取る変数

int ch;

getcharが返す文字の値とEOFを受け取るため、chをint型で宣言しています。

繰り返し入力でも、getcharの戻り値をchar型ではなくint型で受け取ることが大切です。

入力方法を表示する部分

printf("文字列を入力してください。EOFで終了します。\n");

printfで、文字列の入力と終了方法を案内しています。

このメッセージを表示した後、while文による繰り返し入力が始まります。

1文字ずつ読み取る部分

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

このwhile文では、読み取り、代入、比較、出力を繰り返しています。

処理を分けて考えると、次のようになります。

手順処理内容
1getcharで標準入力から1文字を読み取る
2getcharの戻り値をchへ代入する
3chがEOFではないか確認する
4EOFでなければputcharでchを出力する
5while文の先頭へ戻って次の文字を読み取る
6EOFが返されたらwhile文を終了する

この処理によって、入力された文字が1文字ずつ順番に標準出力へ送られます。

while文の条件式を分けて考えよう

次の条件式は、最初は少し複雑に見えるかもしれません。

(ch = getchar()) != EOF

内側から順番に考えると分かりやすくなります。

最初にgetcharが1文字を読み取ります。

getchar()

次に、その戻り値をchへ代入します。

ch = getchar()

代入された値がEOFではないかを比較します。

(ch = getchar()) != EOF

比較結果が真ならwhile文の処理を続け、偽ならwhile文を終了します。

代入部分に丸かっこが必要な理由

条件式では、次の部分を丸かっこで囲んでいます。

(ch = getchar())

この丸かっこによって、getcharの戻り値をchへ代入してから、chとEOFを比較することが明確になります。

丸かっこを省略して次のように書くと、意図した処理にはなりません。

ch = getchar() != EOF

比較演算子!=は、代入演算子=より先に評価されます。そのため、上の書き方は実質的に次の順番で処理されます。

ch = (getchar() != EOF)

この場合、chへ代入されるのは読み取った文字ではなく、比較結果の0または1です。

比較結果chへ代入される値
getcharの戻り値がEOFではない1
getcharの戻り値がEOFである0

これでは、putcharで入力文字を正しく出力できません。

getcharの戻り値をchへ代入してからEOFと比較するため、次の形で記述します。

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

EOFの入力方法

キーボードからEOFを伝える方法は、実行環境によって異なります。

実行環境一般的な入力方法
WindowsのコンソールCtrl+Zを押した後にEnter
UNIXまたはLinuxの端末Ctrl+D

Windowsでは、一般的に行の先頭でCtrl+Zを押し、その後にEnterを押します。

UNIXやLinuxでは、入力待ちの状態でCtrl+Dを押します。ただし、同じ行にまだプログラムへ渡されていない文字がある場合、最初のCtrl+Dではその文字が渡されます。その後、空の入力状態でもう一度Ctrl+Dを押すとEOFとして扱われます。

EOFの操作は、文字そのものを入力しているわけではありません。これ以上入力するデータがないことを端末からプログラムへ伝える操作です。

EOFは入力終了と入力エラーの両方を表す

getcharがEOFを返す理由には、次の2つがあります。

  • 入力の終わりに達した
  • 入力エラーが発生した

getcharの戻り値だけでは、この2つを直接区別できません。

今回のプログラムでは、EOFが返されたら繰り返しを終了するという基本的な処理にしています。入力終了と入力エラーを詳しく区別する方法は、ファイル入出力を学ぶ段階で扱います。

バッファリングとは

getcharは1回の呼び出しで1文字を読み取ります。

しかし、一般的な端末で実行すると、キーを押した瞬間にプログラムが1文字を受け取るのではなく、Enterを押した後にまとめて処理されるように見えることがあります。

これは、入力がバッファを通してプログラムへ渡されるためです。

バッファとは、入力や出力のデータを一時的に保存するための領域です。入力データを一度バッファへためてからプログラムへ渡す仕組みをバッファリングといいます。

入力バッファの流れ

キーボードから文字を入力した場合の一般的な流れは、次のとおりです。

段階処理内容
1キーボードから文字を入力する
2入力した文字が一時的な領域にたまる
3Enterを押して1行分の入力を確定する
4入力した文字と改行文字がプログラムへ渡される
5getcharがバッファから1文字ずつ取り出す

例えば、ABCと入力してEnterを押した場合、入力バッファには次のような文字が入ります。

A  B  C  \n

getcharを繰り返し呼び出すと、次の順番で読み取ります。

getcharの呼び出し読み取る文字
1回目A
2回目B
3回目C
4回目改行文字

getcharは1文字ずつ読み取っていますが、キーボードからの入力はEnterによって1行単位で確定することがあります。

端末の設定や実行環境によって動作は異なりますが、一般的な対話型の環境ではこのような動きになります。

図3:入力バッファから1文字ずつ読み取る流れ

この図から分かること

キーボードから入力した文字は、一般的な端末では一度入力バッファにたまります。Enterを押すと入力が確定し、文字と改行文字がプログラムから読み取れる状態になります。

getcharは、入力バッファに入っている文字を先頭から1文字ずつ読み取ります。

ABCと入力してEnterを押した場合、getcharはA、B、C、改行文字の順番で読み取ります。getcharが1文字入力の関数であっても、キーボード入力がEnterまで待つように見えるのは、このバッファリングが関係しています。

出力にもバッファリングがある

バッファリングは入力だけでなく、出力でも利用されます。

printfやputcharで出力したデータは、すぐに画面へ送られる場合もあれば、一度出力バッファにためられてから送られる場合もあります。

端末へ接続された標準出力では、改行文字が出力されたタイミングなどで、バッファの内容が画面へ送られることがあります。

そのため、入力を案内するメッセージに改行がない場合、環境によってはメッセージがすぐに表示されない可能性があります。

printf("文字を入力してください: ");

対話型プログラムで表示を確実に送り出す方法もありますが、ここでは、標準入力と標準出力の両方にバッファリングという仕組みが関係していることを押さえておきましょう。

getcharとputcharを学ぶ意味

getcharとputcharの機能は、どちらも1文字を扱うというシンプルなものです。

しかし、この2つの関数を学ぶことで、C言語の入出力に関する大切な考え方を確認できます。

学べること内容
文字単位の入出力1文字ずつ読み書きする基本が分かる
戻り値の扱いgetcharの戻り値をint型で受け取る理由が分かる
EOFの判定入力の終わりを判断する方法が分かる
while文との組み合わせ入力が終わるまで繰り返す基本形が身につく
入力バッファEnterや改行文字が入力に与える影響が分かる
出力エラーputcharも処理結果を戻り値で返すことが分かる

getcharとputcharは、単なる1文字入出力の関数ではありません。文字、戻り値、EOF、繰り返し、バッファリングを一緒に学べる関数です。

標準入出力関数の使い分け

標準入出力関数には、それぞれ得意な処理があります。

関数得意な処理主に扱う単位
getchar標準入力から1文字を読み取る1文字
putchar標準出力へ1文字を書き込む1文字
fgets大きさを指定して1行を読み取る文字列
puts文字列を出力して改行する文字列
scanf書式に従ってデータを読み取る数値や文字列など
printf書式に従ってデータを出力する数値や文字列など

1文字だけを調べたり変換したりする場合は、getcharとputcharが向いています。

空白を含む1行の文字列を読み取りたい場合は、fgetsが適しています。文字列を表示した後に改行したい場合は、putsを利用できます。

整数や実数などを指定した形式で入力したい場合はscanf、数値や文字列を組み合わせて表示したい場合はprintfが役立ちます。

処理に合った関数を選ぼう

標準入出力関数を選ぶときは、何を扱いたいのかを先に考えます。

  • 1文字を入力したい場合はgetcharを使う
  • 1文字を出力したい場合はputcharを使う
  • 1行の文字列を入力したい場合はfgetsを使う
  • 文字列を表示して改行したい場合はputsを使う
  • 書式を指定して入力したい場合はscanfを使う
  • 書式を指定して出力したい場合はprintfを使う

例えば、入力された文字が英字か数字かを1文字ずつ調べる処理では、getcharが使いやすいでしょう。

名前や文章などを1行単位で入力する処理では、fgetsが適しています。複数の数値を指定した形式で表示する場合は、printfが便利です。

関数名を暗記するだけではなく、どのような場面に向いているかを一緒に理解することが大切です。

標準入出力関数を使うときの確認事項

標準入出力関数を使うときは、次の点を確認しましょう。

  • stdio.hをインクルードしているか
  • 関数が受け取る引数を確認したか
  • 関数が返す値の型を確認したか
  • 戻り値がEOFになる場合を考えたか
  • getcharの戻り値をint型で受け取っているか
  • Enterによる改行文字が入力に含まれることを理解しているか
  • 入力がバッファを通して渡されることを理解しているか
  • 1文字、文字列、書式付きデータのどれを扱うのか確認したか

特にgetcharでは、戻り値をint型で受け取り、putcharへ渡す前にEOFではないことを確認するのが基本です。

繰り返し入力では、次の形が重要になります。

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

この形では、getcharによる読み取り、chへの代入、EOFとの比較を順番に行っています。

標準入出力関数を学ぶときは、関数名だけではなく、入力元、出力先、引数、戻り値、EOF、改行、バッファリングまで意識すると、C言語の入出力の仕組みをしっかり理解できるようになります。