
C言語基礎|論理否定と条件の書き換え
はじめに:条件は「同じ意味でも、読みやすさが変わる」
C言語でプログラムを書いていると、同じ判定なのに
- ある書き方はスッと読める
- 別の書き方は一瞬考え込む
…みたいなこと、よく起きます。
とくに 入力チェック や ループの継続条件 は、条件式が長くなりがち。
そこで役に立つのが 論理否定演算子 ! と 条件の書き換え(ド・モルガンの法則) です。
ここでは、
- ! が何をしているのか
- 継続条件と終了条件の関係
- ド・モルガンの法則で「同じ意味に変換できる」こと
を、表と図でやさしく整理していきます。
サンプル:入力値が 10〜99 でなければ再入力
「2桁の整数(10〜99)だけ受け付ける入力チェック」プログラムを例に解説します。
プロジェクト名:chap4-3-1 ソースファイル名:chap4-3-1.c
Visual Studio でこのプログラムを実行するには、SDLチェック設定を変更しておく必要があります。
1.プロジェクト名を右クリックして、「プロパティ」をクリックします。
2.「C/C++」→「全般」→「SDLチェック」を「いいえ」に切り替えて「OK」をクリックします。
// 2桁の整数(10〜99)のみ受け付け、OKなら結果を表示
#include <stdio.h>
int main(void)
{
int code;
do {
printf("Enter a 2-digit code (10 to 99): ");
scanf("%d", &code);
} while (code < 10 || code > 99); // 継続条件:不当なら繰り返す
printf("Accepted. Your code is %d.\n", code);
return 0;
}実行例
Enter a 2-digit code (10 to 99): 7
Enter a 2-digit code (10 to 99): 120
Enter a 2-digit code (10 to 99): 42
Accepted. Your code is 42.まずは復習:do文の継続条件は「繰り返す条件」
このサンプルの do 文はこうです。
do {
...
} while (code < 10 || code > 99);ここでの while (式) の式は 制御式。
その意味は 式が真(非0)なら繰り返す です。
つまり今回の制御式は、
- code が 10 未満、または 99 より大きい
→ 範囲外(不当)なら繰り返す
という 継続条件 になっています。
論理否定演算子 ! は何をする演算子?
!(論理否定)は、ざっくり言うと
- 真っぽいものを偽に
- 偽っぽいものを真に
ひっくり返す演算子です。
表:論理否定演算子の意味
| 形式 | 意味 | 結果の型 |
|---|---|---|
| !a | a が 0 なら 1、そうでなければ 0 | int |
C言語の条件式では、慣習として
- 0 が偽
- 0以外が真
です。だから ! は「0かどうか」を判定して反転させている、と思うと理解が早いです。
例:値の反転イメージ
| a | !a |
|---|---|
| 0 | 1 |
| 5 | 0 |
| -3 | 0 |
「不当なら続ける」を「妥当でないなら続ける」に書き換える
元の制御式(継続条件)はこれでした。
code < 10 || code > 99これは「code が範囲外か?」という判定です。
一方で「code が範囲内か?」という判定はこう書けます。
code >= 10 && code <= 99そして「範囲内ではないか?」(妥当ではないか?)は、これの否定なのでこうなります。
!(code >= 10 && code <= 99)つまり、次の2つは 同じ意味 になります。
表:同じ意味になる2つの条件式
| 目的 | 条件式 | 日本語のニュアンス |
|---|---|---|
| 継続条件(不当なら繰り返す) | code < 10 || code > 99 | 範囲外ならやり直し |
| 終了条件の否定(妥当でなければ繰り返す) | !(code >= 10 && code <= 99) | 範囲内でないならやり直し |
どっちが良いかは「好み」でもありますが、文脈で読みやすいほうを選べるのが強みです。
継続条件と終了条件はコインの裏表
同じ意味を、見え方を変えて表現するとこうなります。
① 継続条件(不当なら続ける)
code < 10 || code > 99
② 終了条件(妥当なら終わる)の否定
!(code >= 10 && code <= 99)
- ① は「続ける理由」を書いている。
- ② は「終わる理由」の反対を書いている。
中身は同じでも、読み手が理解しやすい方向が変わるんですね。
ド・モルガンの法則:否定を中に入れると && と || が入れ替わる
ここが本題のキモです。
ド・モルガン(C言語風)
| 元の式 | 同じ意味の式 |
|---|---|
| x && y | !( !x || !y ) |
| x || y | !( !x && !y ) |
つまり、否定を配る(内側に押し込む)ときは
- && と || が入れ替わる。
- 各条件が否定される。
というルールです。
実際に変形してみる(今回の条件で確認)
「妥当」はこうでした。
(code >= 10 && code <= 99)
これを否定したものが「妥当でない」。
!(code >= 10 && code <= 99)
ここでド・モルガンを使うと、
- (A && B) の否定は (!A || !B)
なので、
- !(code >= 10) || !(code <= 99)
さらに比較の否定は次のように書けます。
- !(code >= 10) は code < 10
- !(code <= 99) は code > 99
だから最終的に、
code < 10 || code > 99
に戻ります。ちゃんと一致しましたね。
表:変形のステップ
| ステップ | 式 |
|---|---|
| 妥当 | code >= 10 && code <= 99 |
| 妥当でない(否定) | !(code >= 10 && code <= 99) |
| ド・モルガン適用 | !(code >= 10) || !(code <= 99) |
| 比較の否定を整理 | code < 10 || code > 99 |
どっちの書き方が読みやすい?(実務の感覚)
わりと実務ではこういう基準で選ぶことが多いです。
| こういう時 | 読みやすい傾向 |
|---|---|
| 「範囲外ならやり直し」みたいに例外側を強調したい | code < 10 || code > 99 |
| 「範囲内」というルールを強調したい | !(code >= 10 && code <= 99) ではなく、むしろ code >= 10 && code <= 99 を終了条件側に回す発想が合う |
| 条件が複雑で否定が入り乱れる | ド・モルガンで否定を整理して、否定記号 ! を減らす |
特に、!( ... ) が何重にもなると急に読みづらくなるので、
「否定を配ってスッキリさせる」ド・モルガンはかなり頼れます。
ここで登場した命令の書式まとめ
do-while 文
| 形式 | 役割 |
|---|---|
| do { ... } while (式); | まず本体を実行してから式を評価。式が真なら繰り返す。 |
論理否定
| 形式 | 役割 |
|---|---|
| !a | a が 0 なら 1、それ以外なら 0(真偽を反転) |
論理積と論理和
| 演算子 | 意味 |
|---|---|
| x && y | 両方が真なら真 |
| x || y | どちらかが真なら真 |
まとめ:条件の書き換えは「読みやすさの武器」
- ! は真偽を反転する。
- 継続条件と終了条件は、見方を変えただけで同じ意味になりうる。
- ド・モルガンの法則で、否定を整理して読みやすい条件式にできる。
条件式は「正しい」だけじゃなく、「読みやすい」も超大事。
この章を押さえると、入力チェックや複雑な分岐がグッと書きやすくなります。
