C言語基礎|do文による入力チェック

はじめに:入力チェックは「優しさ」と「安全」の基本セット

プログラムって、人が入力する以上、どうしても 想定外の値 が入ってきます。
たとえば「1〜12の月を入力してね」と言っても、0 や 99 を入れられること、普通にあります。

そこで大事になるのが 入力チェック
そして、C言語で入力チェックの定番パターンが do文(do-while) なんです。

do文は「まず1回は必ず実行する」ので、入力を促す処理と相性が抜群。
入力が正しくなるまで「もう一回入力してね」を繰り返す、あの動きがスッキリ書けます。

do文による入力チェックって何をしているの?

やっていることはシンプルで、流れはこうです。

  1. 入力を促す(必ず1回は実行)
  2. 入力値を受け取る
  3. 妥当かどうか判定する(制御式)
  4. 不当なら 1 に戻ってやり直し

つまり、不当な値の間だけループを続けるのがポイントです。

サンプル:曜日番号の入力チェック(0〜6だけ受け付ける)

ここでは、「曜日を 0〜6 の番号で入力してもらい、曜日名を表示する」プログラムを例に解説します。

プロジェクト名:chap4-2-1 ソースファイル名:chap4-2-1.c

Visual Studio でこのプログラムを実行するには、SDLチェック設定を変更しておく必要があります。
1.プロジェクト名を右クリックして、「プロパティ」をクリックします。
2.「C/C++」→「全般」→「SDLチェック」を「いいえ」に切り替えて「OK」をクリックします。

// 曜日番号を入力チェックして曜日名を表示(0〜6のみ受け付ける)
#include <stdio.h>

int main(void)
{
    int day;   // 曜日番号(0=Sun ... 6=Sat)

    do {
        printf("Enter day number (0=Sun ... 6=Sat): ");
        scanf("%d", &day);
    } while (day < 0 || day > 6);   // day が不当な値なら繰り返す

    printf("You selected: ");

    switch (day) {
    case 0: printf("Sunday");    break;
    case 1: printf("Monday");    break;
    case 2: printf("Tuesday");   break;
    case 3: printf("Wednesday"); break;
    case 4: printf("Thursday");  break;
    case 5: printf("Friday");    break;
    case 6: printf("Saturday");  break;
    }

    printf("\n");
    return 0;
}

実行例

Enter day number (0=Sun ... 6=Sat): 9
Enter day number (0=Sun ... 6=Sat): -1
Enter day number (0=Sun ... 6=Sat): 5
You selected: Friday

不当な値(9 や -1)だと入力し直しになって、妥当な値(0〜6)で抜けます。

do文の書式(構文)を確認しよう

do文の基本形はこれです。

要素書式意味
開始doループ開始
ループ本体文 / 複合文繰り返したい処理
継続判定while (式);式が真(非0)なら繰り返す。

図:do文の構文イメージ

do
    ループ本体(入力など)
while (制御式);

注意ポイント:最後にセミコロンが必要です。
これ、地味に忘れがちです…!

入力チェックの核心:制御式が「不当な間だけ真」になっている

今回の制御式はこれです。

day < 0 || day > 6

これは日本語にすると、

  • day が 0 未満 または
  • day が 6 より大きい

つまり 0〜6の範囲外なら不当、という判定ですね。

論理OR演算子 || の意味(入力チェックで超頻出)

|| は「または」「どちらか一方でも真なら真」です。

条件A条件BA || B

今回なら、

  • day < 0 が真(例:-1)
  • または day > 6 が真(例:9)

どっちかが成立した時点で 不当 → もう一度入力 になります。

do文入力チェックの流れ(制御フロー)

文書だけだとモヤっとしやすいので、流れを図にします。

(1) 入力を促す
(2) day を読み込む
(3) day < 0 || day > 6 を評価
      ├─ 真(不当) → (1)に戻る
      └─ 偽(妥当) → ループ終了 → switchで表示

ここがdo文の気持ちよさで、
入力 → 判定 → ダメなら入力へ戻る が一直線に書けます。

do文を抜けた後の保証:day は必ず 0〜6 になる

この入力チェックの“嬉しい副作用”がこれです。

  • do文を抜けた時点で、day は必ず 0〜6 のどれか

だから後続の switch は安心して書けます。
範囲外が来ない前提が作れるので、コード全体が安定します。

タイミングday に入りうる値
do文の途中何でもあり(不当も来る)
do文の終了後0〜6 のみ(妥当のみ)

switch文の役割(入力チェックと相性がいい理由)

switch は「値によって処理を分岐」する文です。
今回だと day の値に応じて曜日名を表示します。

switch文の書式

要素書き方役割
分岐対象switch (式)どの値で分岐するか
各分岐case 定数:定数に一致した時の処理
それ以外default:どれにも一致しない時
抜けるbreak;switchを終了する

今回 default がなくてもOKな理由

do文で 0〜6 に限定しているので、default が不要になっています。
(もちろん、保険で default を書くのもアリです)

入力チェックでありがちな注意点(ちょい大事)

ありがち何が起きる?対策
数字じゃない文字を入力されるscanf が失敗して値が更新されない。本格対応は入力バッファ処理が必要(次のステップで扱うと◎)
範囲条件を逆に書くずっと抜けられない / すぐ抜ける。継続条件を日本語で言ってから式にする。

今回のテーマは「範囲チェック」なので、まずは 数値が入る前提でしっかり形を覚えるのが良いです。
文字入力対策は、次のレベルで一気に強くなれます。

まとめ:do文入力チェックの合言葉

  • do文は「まず1回やる」
  • 制御式は「不当な間だけ真」にする。
  • ループを抜けたら「妥当な値が保証される」

この3つが揃うと、入力チェックはかなり気持ちよく書けます。