C言語のきほん|条件式の反転

条件をひっくり返すだけで読みやすくなる!真・偽の主役を入れ替えて、分岐をスッキリ整理しよう。

if~else は「真ならA、偽ならB」という2択の分岐でしたね。
ここで面白いのが、条件式を反転すると、真と偽の担当を入れ替えられることです。

たとえば「範囲内ならOK、範囲外ならNG」という処理でも、

  • OK を先に書きたい(if側に書きたい)
  • NG を先に書きたい(if側に書きたい)

どちらの書き方もできます。
どっちが正しいというより、どっちの方が意図が伝わるかがポイントです。

この記事では、条件式を反転する代表的な方法として

  • 条件そのものを逆の形に書き換える
  • 否定演算子 ! を使って反転する

の2つを、具体例と一緒に丁寧に説明します。

真と偽を入れ替えると何が嬉しい?

条件式を反転すると、if 側に「先に処理したいケース」を置けます。

よくあるのは、こういう考え方です。

  • 正常系を if に書いて、異常系を else にする
  • 逆に、異常系を if に書いて早めに対処し、正常系を else にする

どちらもありですが、入力チェックなどは「異常系を先に書く」方が読みやすいことも多いです。

反転の基本パターン:範囲内 ↔ 範囲外

パターンA:範囲内を if に置く(正常系が先)

ファイル名:8_5_1.c

#include <stdio.h>

int main(void)
{
    int score;

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

    if (score >= 0 && score <= 100) {
        printf("入力された点数は有効です。\n");
    } else {
        printf("点数は0〜100の範囲で入力してください。\n");
    }

    return 0;
}

パターンB:範囲外を if に置く(異常系が先)

ファイル名:8_5_2.c

#include <stdio.h>

int main(void)
{
    int score;

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

    if (score < 0 || score > 100) {
        printf("点数が範囲外です。入力を見直してください。\n");
    } else {
        printf("入力された点数は有効です。\n");
    }

    return 0;
}

どちらも結果は同じですが、「何を先に処理したいか」が見た目に出ます。

どうして (score < 0 || score > 100) が反転なの?

範囲内の条件は

  • score >= 0
  • score <= 100
  • 両方必要なので &&

範囲外は「範囲内でない」です。つまり

  • 0未満 または 100より大
  • どちらかでアウトなので ||

数直線イメージ(文字)にするとこうです。

!(否定演算子)で反転する書き方

条件式をひっくり返したいとき、否定演算子 ! が使えます。

例:範囲内を否定して範囲外にする

ファイル名:8_5_3.c

if (!(score >= 0 && score <= 100)) {
    printf("点数が範囲外です。\n");
} else {
    printf("入力された点数は有効です。\n");
}

この !(範囲内) は、範囲外と同じ意味になります。

! を使うときのコツ

! を使うと短く書けることがありますが、否定が増えると読みにくくなることもあります。
読みやすさは大事なので、

  • 範囲外を素直に書いた方が読みやすいなら、score < 0 || score > 100
  • 範囲内の条件がすでにあって、それを反転したいなら、!(範囲内)

という使い分けがちょうどいいです。

反転の定番ルール(覚えると速い)

条件を反転するときは、次の対応がよく出ます。

元の条件反転すると
A == BA != B
A < BA >= B
A <= BA > B
A > BA <= B
A >= BA < B

論理演算子の反転もよく使います(これは慣れてからでOKですが、便利です)。

元の条件反転すると
A && B!A || !B
A || B!A && !B

この考え方は、条件式を整理するときにすごく役立ちます。

実践問題:年齢判定

年齢(整数値)を入力し、学生料金の対象かどうかを判定するプログラムを作成してください。

学生料金の条件
15歳以上25歳以下

実行例1(対象)

年齢を入力してください > 15
学生料金の対象です。

実行例2(対象外)

年齢を入力してください > 26
学生料金の対象ではありません。

解答例(範囲内を if にする)

ファイル名:8_5_4.c

#include <stdio.h>

int main(void)
{
    int age;

    printf("年齢を入力してください > ");
    scanf("%d", &age);

    if (age >= 15 && age <= 25) {
        printf("学生料金の対象です。\n");
    } else {
        printf("学生料金の対象ではありません。\n");
    }

    return 0;
}

解説

  • 下限(15)も上限(25)も含めたいので >= と <=
  • 両方必要なので &&

「範囲内を判定したいなら &&」が基本形です。

実践問題:年齢範囲の判定

年齢(整数値)を入力し、映画のシニア割引の対象かどうかを判定するプログラムを作成してください。

シニア割引の対象
65歳以上80歳未満
80歳は対象外とします。

実行例1(対象)

年齢を入力してください > 65
シニア割引の対象です。

実行例2(対象外)

年齢を入力してください > 80
シニア割引の対象ではありません。

解答例(反転して「対象外」を if にする)

ファイル名:8_5_5.c

#include <stdio.h>

int main(void)
{
    int age;

    printf("年齢を入力してください > ");
    scanf("%d", &age);

    /* 対象は 65以上80未満。反転して対象外を先に判定する */
    if (age < 65 || age >= 80) {
        printf("シニア割引の対象ではありません。\n");
    } else {
        printf("シニア割引の対象です。\n");
    }

    return 0;
}

解説

対象は age >= 65 && age < 80 ですが、ここでは「対象外」を先に処理したいので反転しています。

  • 対象外は age < 65 または age >= 80
  • どちらかで対象外なので ||

境界の 80 は「未満」なので、反転側は >= 80 になります。

実践問題:うるう年判定

西暦年を入力し、その年の2月の最終日が 28日か 29日かを判定するプログラムを作成してください。

うるう年の判定基準

  • 4で割り切れる → 原則うるう年
  • ただし100で割り切れる → 平年
  • ただし400で割り切れる → うるう年

実行例(うるう年)

西暦年を入力してください > 2000
2000年の2月の最終日は29日です。

実行例(平年)

西暦年を入力してください > 2100
2100年の2月の最終日は28日です。

解答例

ファイル名:8_5_6.c

#include <stdio.h>

int main(void)
{
    int year;

    printf("西暦年を入力してください > ");
    scanf("%d", &year);

    /* うるう年判定 */
    if ((year % 400 == 0) || (year % 4 == 0 && year % 100 != 0)) {
        printf("%d年の2月の最終日は29日です。\n", year);
    } else {
        printf("%d年の2月の最終日は28日です。\n", year);
    }

    return 0;
}

解説

条件は少し長いですが、読み方は順番にいけば大丈夫です。

  • 400で割り切れるならうるう年(例外の例外)
  • そうでなければ、4で割り切れて、100で割り切れないならうるう年
  • それ以外は平年

この条件式は、括弧を付けておくと読みやすくて安心です。