C言語の基本|if文のネスト

大きな条件を通過したら、次の条件へ。if文を入れ子にして、段階的な判断を分かりやすく組み立てよう。

プログラムでは、1つの条件だけで処理を決められないことがあります。

たとえば、機器のバッテリー残量を確認する場合、最初に入力値が0から100までの正しい範囲に入っているかを調べなければなりません。その確認を通過した後で、残量に応じた動作モードを選びます。

このように、最初の条件を満たした場合に、さらに別の条件を調べる仕組みがif文のネストです。ネストは入れ子とも呼ばれ、外側のif文の中に別のif文を記述します。

判断を一度に行うのではなく、次のように段階を分けて考えるのがポイントです。

  • 最初に大きな条件を確認する
  • 条件を満たした場合だけ内側へ進む
  • 内側で、より細かな条件を確認する
  • 外側の条件を満たさない場合は別の処理へ進む

図1:外側の条件から内側の条件へ進む流れ

この図から分かること

外側のif文は、内側の処理へ進んでよいかを判断する入口として働きます。

外側の条件が真なら内側のif文へ進み、さらに細かい判定を行います。外側の条件が偽の場合は内側へ入らないため、内側の条件式は評価されません。

ネスト構造とは

ネストとは、ある制御構造の中に、別の制御構造を組み込むことです。

if文の中にif文を書くと、次のような段階的な条件分岐を作れます。

if (条件式1) {
    if (条件式2) {
        文1;
    } else {
        文2;
    }
} else {
    文3;
}

この構文では、条件式1が外側の条件、条件式2が内側の条件です。

処理の対応を表にすると、次のようになります。

条件式1条件式2実行される処理
文1
文2
評価しない文3

条件式1が偽になった場合、プログラムは外側のelseへ進みます。内側のif文が含まれるブロックには入らないため、条件式2は評価されません。

外側と内側で役割を分ける

ネストされたif文は、外側と内側の役割を分けると読みやすくなります。

位置主な役割
外側のif処理を進めてよいか確認する
内側のif通過したデータを細かく分類する
外側のelse入力エラーなどを処理する
内側のelse内側のどの条件にも当てはまらない場合を処理する

たとえば、入力されたバッテリー残量を使う場合は、次のように分けられます。

  • 外側では0以上100以下かを確認する
  • 内側では残量に応じた動作モードを決める
  • 外側のelseでは範囲外の入力を知らせる

このように、条件の意味に合わせて階層を作ると、処理の流れが自然に読めるようになります。

else if文とネストの関係

if~else if~elseも、条件を段階的に確認する書き方です。

else ifは、前の条件が偽だった場合に、次のif文を調べる形になっています。

if (条件式1) {
    文1;
} else if (条件式2) {
    文2;
} else {
    文3;
}

この処理は、考え方としては次のような入れ子として捉えられます。

if (条件式1) {
    文1;
} else {
    if (条件式2) {
        文2;
    } else {
        文3;
    }
}

通常は、同じ段階の選択肢を順番に調べる場合にはelse ifを使ったほうが読みやすくなります。

一方、入力の正当性を確認した後に別の種類の条件を調べる場合は、if文を明確にネストすると条件の階層を表しやすくなります。

ネストを書くときはインデントを揃える

ネスト構造では、どのif文がどの階層にあるかを見た目で判断できるようにすることが大切です。

次の点を意識すると読みやすくなります。

  • 内側へ入るたびにインデントを1段深くする
  • 同じ階層の文は同じ位置に揃える
  • 処理が1文だけでも波括弧を付ける
  • 開始側の波括弧と終了側の波括弧の対応を確認する
  • 空行を入れすぎず、関連する処理を近くに置く

インデントそのものはプログラムの実行結果を変えません。しかし、階層を読み間違えると、修正する場所や条件の関係を誤解しやすくなります。

入力値を確認してから動作モードを選ぶ

次のプログラムでは、バッテリー残量を入力し、最初に0以上100以下であるかを確認します。

入力が正しい場合だけ、内側のif文で動作モードを選びます。

バッテリー残量選択するモード
70以上高出力モード
30以上70未満標準モード
30未満省電力モード
0未満または100より大きい入力エラー
有効なバッテリー残量から動作モードを選ぶプログラム

ファイル名:8_7_1.c

#include <stdio.h>

int main(void)
{
    int battery;

    printf("バッテリー残量を入力してください(0~100)> ");
    scanf("%d", &battery);

    /* 外側のifで入力値の範囲を確認する */
    if (battery >= 0 && battery <= 100) {

        /* 有効な入力の場合だけ動作モードを選ぶ */
        if (battery >= 70) {
            printf("高出力モードを使用できます。\n");
        } else if (battery >= 30) {
            printf("標準モードで動作します。\n");
        } else {
            printf("省電力モードへの切り替えをおすすめします。\n");
        }

    } else {
        printf("入力エラー:0~100の範囲で入力してください。\n");
    }

    return 0;
}
実行結果の例

バッテリー残量が有効な範囲の場合は、内側のif文まで進みます。

バッテリー残量を入力してください(0~100)> 45
標準モードで動作します。

入力値が範囲外の場合は、外側のelseが実行されます。

バッテリー残量を入力してください(0~100)> 120
入力エラー:0~100の範囲で入力してください。
プログラムの詳しい解説

外側の条件式では、batteryが0以上であり、さらに100以下であるかを確認しています。

battery >= 0 && battery <= 100

45を入力した場合は、2つの条件を両方満たすため、外側のifブロックへ入ります。

外側のブロック内では、最初にbattery >= 70を調べます。45ではこの条件が偽になるため、次のbattery >= 30を評価します。

45は30以上なので、この条件が真になり、標準モードのメッセージが表示されます。

120を入力した場合、battery <= 100が偽になります。そのため、外側のifブロックには入らず、外側のelseが実行されます。この場合、内側にあるbattery >= 70などの条件は評価されません。

図2:入力チェックと動作モード判定のネスト

この図から分かること

ネスト構造では、外側の条件が内側の判定を行うための前提になります。

45は有効な入力なので、内側の条件まで進んで標準モードに分類されます。一方、120は外側の条件を満たさないため、その時点で入力エラーとなり、内側の動作モード判定は行われません。

エラー判定と本処理を分ける考え方

ネスト構造は、入力の正当性を確認してから本来の処理へ進む場合に便利です。

処理を次の2段階に分けられます。

  1. 外側で入力値を検査する
  2. 内側で有効な入力に対する処理を行う

この構成には、次の利点があります。

  • 不正な入力で計算や細かな判定を行わずに済む
  • 内側には正常な入力を前提とした処理だけを書ける
  • 入力チェックと本処理の関係が見やすくなる
  • エラーメッセージを書く場所が明確になる

ただし、ネストを深くしすぎると、どの条件の内側にいるのか分かりにくくなります。条件の階層に意味がある場合に使うことが大切です。

ネストを深くしすぎないための注意点

注意点問題になりやすいこと書き方のポイント
インデントが不統一条件の階層を見失う1段ごとに同じ幅で下げる
波括弧を省略する処理範囲を誤解しやすい1文でも波括弧を付ける
条件を無計画に追加するネストが深くなりすぎる条件の役割を先に整理する
外側と内側の役割が同じ階層にした意味が伝わらない大きな条件と細かな条件に分ける
エラーと正常処理が混在する処理の目的が追いにくい入力チェックと本処理を分ける

ネストを使う前に、条件同士の関係を確認してみましょう。

一方の条件を満たした場合にだけ、もう一方の条件を調べる必要があるなら、ネストが自然です。すべての条件が同じ段階の選択肢なら、else ifで横に並べたほうが読みやすい場合があります。

会員区分と購入金額から割引額を計算する

次のプログラムでは、購入金額と会員かどうかを入力し、店舗の割引額を計算します。

割引ルールは次のとおりです。

会員区分購入金額割引率
会員8000円以上12%
会員8000円未満5%
非会員8000円以上5%
非会員8000円未満割引なし

入力値には次の条件があります。

  • 購入金額は0円以上
  • 会員なら1を入力する
  • 非会員なら0を入力する
  • 会員区分に0と1以外が入力された場合はエラーにする
会員区分と購入金額を段階的に判定するプログラム

ファイル名:8_7_2.c

#include <stdio.h>

int main(void)
{
    int price;
    int is_member;
    int discount;
    int payment;

    printf("購入金額を入力してください(円)> ");
    scanf("%d", &price);

    printf("会員ですか?(1:はい、0:いいえ)> ");
    scanf("%d", &is_member);

    /* 外側のifで入力値が正しいかを確認する */
    if (price >= 0 && (is_member == 0 || is_member == 1)) {

        /* 最初に会員かどうかを判定する */
        if (is_member == 1) {

            /* 会員の場合の購入金額判定 */
            if (price >= 8000) {
                discount = price * 12 / 100;
            } else {
                discount = price * 5 / 100;
            }

        } else {

            /* 非会員の場合の購入金額判定 */
            if (price >= 8000) {
                discount = price * 5 / 100;
            } else {
                discount = 0;
            }
        }

        payment = price - discount;

        printf("割引額は%d円です。\n", discount);
        printf("支払金額は%d円です。\n", payment);

    } else {
        printf("入力エラー:金額は0以上、会員区分は1か0で入力してください。\n");
    }

    return 0;
}
実行結果の例

8000円以上を購入した会員の場合は、12%割引になります。

購入金額を入力してください(円)> 9000
会員ですか?(1:はい、0:いいえ)> 1
割引額は1080円です。
支払金額は7920円です。

8000円未満を購入した非会員の場合は、割引なしになります。

購入金額を入力してください(円)> 4000
会員ですか?(1:はい、0:いいえ)> 0
割引額は0円です。
支払金額は4000円です。

入力が正しくない場合は、割引計算を行いません。

購入金額を入力してください(円)> 5000
会員ですか?(1:はい、0:いいえ)> 3
入力エラー:金額は0以上、会員区分は1か0で入力してください。
プログラムの詳しい解説

最も外側のif文では、2つの入力が正しいかを確認しています。

price >= 0 && (is_member == 0 || is_member == 1)

購入金額が0以上であり、さらに会員区分が0または1の場合にだけ、割引計算へ進みます。

入力が正しい場合、次にis_member == 1を使って会員かどうかを判定します。

会員の場合は、内側で購入金額が8000円以上かを調べます。

if (price >= 8000) {
    discount = price * 12 / 100;
} else {
    discount = price * 5 / 100;
}

非会員の場合も、別の内側のif文で購入金額を判定します。

if (price >= 8000) {
    discount = price * 5 / 100;
} else {
    discount = 0;
}

割引額が決まった後、購入金額から割引額を引いて支払金額を計算します。

payment = price - discount;

このプログラムでは、条件の階層が割引ルールの構造と一致しています。

  • 第1段階は入力値が正しいか
  • 第2段階は会員か非会員か
  • 第3段階は購入金額が8000円以上か

図3:割引ルールを表す3段階のネスト

この図から分かること

このネスト構造では、条件を一度に判定しているのではなく、意味の異なる3つの段階に分けています。

入力が不正なら、会員区分や購入金額による割引判定は行いません。入力が正しい場合だけ会員区分へ進み、その結果に応じて購入金額を確認します。

ネストは、条件を適当に内側へ追加するための書き方ではありません。実際のルールに親子関係や前提条件があるとき、その階層に合わせてif文を配置すると、処理の意図が伝わりやすくなります。