C言語のきほん|改行が残る問題を解決しよう

文字が入力できない…それ、改行のせいかも。入力バッファの仕組みを知ってスッキリ解決しよう。

scanf で数値入力はうまくいくのに、次に %c で文字を入力しようとすると「あれ?入力できない!」となることがあります。
これは初心者あるあるで、つまずいて当然のポイントです。

原因は、プログラムが壊れているわけではなく、scanf の仕様にあります。
具体的には、数値入力のあとに Enter を押したときの 改行文字(\n) が入力バッファに残り、それを %c が先に読んでしまう、という現象です。

この記事では、

  • 入力バッファとは何か
  • なぜ改行が残るのか
  • なぜ %c だけ影響を受けやすいのか
  • どう直すのが安全で実用的か

を、例と一緒にやさしく整理していきます。
ここを理解できると、入力処理が一気に安定して書けるようになります。

入力バッファと改行文字の仕組み

キーボードで入力した文字は、すぐに scanf に渡されるのではなく、まず 入力バッファ に入ります。
そして Enter を押したタイミングで入力が確定し、scanf がそこから必要な分だけ読み取ります。

ここがポイントで、Enter を押すと 改行文字(\n) も一緒にバッファへ入ります。

イメージとしてはこんな感じです。

scanf("%d", &n1); は、この中から整数として必要な部分(123)を読み取ります。
でも、読み取ったあとに改行文字 \n が残ってしまうことがあります。

scanf("%d") のあとに残りやすいもの
'\n'

この「残った \n」が、次の %c にとって厄介者になります。

文字入力ができない典型パターン

まず、問題が起きる形を、シンプルな別例で確認します。
メッセージも別の日本語に置き換え、コメントも日本語にしています。

うまくいかない例(改行が残る)

ファイル名:5_10_1.c

#include <stdio.h>

int main(void)
{
    int first;
    int second;
    char mark;

    printf("数値を入力してください > ");
    scanf("%d", &first);

    printf("記号を1文字入力してください > ");
    scanf("%c", &mark);  /* ここで入力できないことがある */

    printf("次の数値を入力してください > ");
    scanf("%d", &second);

    printf("\n入力結果: %d, %c, %d\n", first, mark, second);

    return 0;
}

期待する動き

数値を入力してください > 123
記号を1文字入力してください > A
次の数値を入力してください > 456

実際に起きがちな動き

数値を入力してください > 123
記号を1文字入力してください > 次の数値を入力してください > 456

「記号を入力してください」のところで、入力したはずの A を受け付けてくれないように見えます。
実は、mark には A ではなく、改行文字 \n が入ってしまっています。

なぜ %c だけが影響を受けやすいのか

%d や %lf は、入力の前に空白類(スペース、改行、タブ)を読み飛ばしてから読み取る動きになっています。
だから、改行が残っていても次の数値入力は意外と進められることが多いです。

一方、%c は「次の1文字」をそのまま読みます。
空白も改行も「1文字」として扱うので、残っている \n を読んでしまいます。

整理するとこうです。

変換指定空白や改行を読み飛ばすか影響
%d読み飛ばす改行が残っていても問題になりにくい
%lf読み飛ばす同上
%c読み飛ばさない改行を読んでしまいがち

この仕様を知っているだけで、「あ、そういうことか!」と納得しやすくなります。

解決方法1:getcharで改行を読み捨てる

1つ目の方法は、scanf("%d", &first); の直後に getchar を入れて、残った改行文字を1文字読み捨てる方法です。

修正版(getchar方式)

ファイル名:5_10_2.c

#include <stdio.h>

int main(void)
{
    int first;
    int second;
    char mark;

    printf("数値を入力してください > ");
    scanf("%d", &first);

    (void)getchar();  /* 残った改行を読み捨てる */

    printf("記号を1文字入力してください > ");
    scanf("%c", &mark);

    printf("次の数値を入力してください > ");
    scanf("%d", &second);

    printf("\n入力結果: %d, %c, %d\n", first, mark, second);

    return 0;
}

この方法のポイント

  • 直前の入力で残った \n を消してから %c を読む
  • 仕組みがわかりやすい(改行を捨てたんだなと見て分かる)

ただし、入力の状況によっては改行以外の空白が残ることもあるので、場面によってはもう少し工夫が必要になることがあります(複雑な入力を扱うときに出てきます)。

解決方法2:%c の前にスペースを入れる(おすすめ)

2つ目の方法は、scanf の書式文字列で %c の前に半角スペースを入れる方法です。

scanf(" %c", &mark);

この半角スペースには意味があって、scanf は書式文字列中の空白を見つけると、入力側の空白類(スペース、改行、タブなど)を読み飛ばします。
その結果、残っている \n を自動でスキップしてから、次の有効な1文字を読んでくれます。

修正版(スペース付き%c方式)

ファイル名:5_10_3.c

#include <stdio.h>

int main(void)
{
    int first;
    int second;
    char mark;

    printf("数値を入力してください > ");
    scanf("%d", &first);

    printf("記号を1文字入力してください > ");
    scanf(" %c", &mark);  /* 空白類を読み飛ばしてから1文字読む */

    printf("次の数値を入力してください > ");
    scanf("%d", &second);

    printf("\n入力結果: %d, %c, %d\n", first, mark, second);

    return 0;
}

この方法の良さ

  • 余計な改行や空白があっても、自動的に読み飛ばしてくれる
  • 入力の前処理を別で書かなくてよい
  • %c を使うなら最初からこの形にしておくと安定しやすい

本文でも、この方法が紹介されていて、入門の段階では特におすすめです。

2つの方法をどう使い分ける?

入門の範囲では、基本は「スペース付き%c」でOKです。
ただ、違いを表にしておくとスッキリします。

方法書き方特徴
getcharで読み捨て(void)getchar();1文字だけ読み捨てる。仕組みが見えやすい
スペース付き%cscanf(" %c", &c);空白類をまとめて読み飛ばす。安定して使いやすい

まずは %c を使うときは scanf(" %c", &c); と覚えてしまうのが楽です。

もう少し具体的に、バッファの中で何が起きているか

さっきの「数値→文字」の流れを、バッファ視点で追うと理解が深まります。

数値入力(123 + Enter)

入力バッファ:
'1' '2' '3' '\n'

scanf("%d", &first) が読むのは 123 の部分です。

読み取られる:
'1' '2' '3'

残り:
'\n'

次に scanf("%c", &mark) をすると、残っていた \n が読まれます。

mark に入る:
'\n'

だから、ユーザーが A を入力する前に、もう1文字読めてしまうわけです。

一方、scanf(" %c", &mark) なら、最初の空白指示によって \n を読み飛ばしてくれます。

空白類を読み飛ばす:
'\n'

次の1文字を読む:
'A'

この流れが腑に落ちれば、もう同じ罠にはハマりにくくなります。

よくある勘違い

scanfが壊れているわけではない

入力できないように見えても、scanf("%c") はちゃんと1文字読んでいます。
ただ、その1文字が「改行」だっただけです。

Enterは入力の一部

Enter を押したときの改行は、見えないけれど入力として扱われます。
入力バッファに残るのは仕様なので、対策して使うのが前提になります。

まずはこのルールだけ覚えればOK

入門段階での最短ルールはこれです。

  • 数値のあとに1文字を読むなら scanf(" %c", &c); にする

これだけで、多くの「文字入力できない問題」を回避できます。