閉じる

C言語の比較演算子と論理演算子まとめ(>,<,==,!=,&&,||,!)

C言語で条件分岐や繰り返しを正しく書くためには、比較演算子と論理演算子の理解が欠かせません。

本記事では、><==!=&&||!の基本から、短絡評価や優先順位、よくある初学者のつまずきまでを、サンプルコードと出力例つきで丁寧に解説します。

0と非0による真偽の扱い= と == の取り違えといった重要ポイントも具体例で確認します。

C言語の比較演算子と論理演算子の基本

C言語の真偽値(0/非0)

C言語では、条件式の結果は整数の0(偽)または非0(真)として扱われます

比較演算や論理演算の評価結果も数値として0または1になります。

変数そのものを条件に使った場合は0なら偽、0以外なら真として評価されます。

C言語
// 0と非0の評価、および比較演算の結果は0/1になる例
#include <stdio.h>

int main(void) {
    int a = 0;
    int b = 42;
    int c = -3;

    // 変数を条件として解釈するなら「!= 0」で真偽に正規化して見ると分かりやすい
    printf("a を条件にした評価(a != 0): %d\n", a != 0);  // 0 -> 偽
    printf("b を条件にした評価(b != 0): %d\n", b != 0);  // 1 -> 真
    printf("c を条件にした評価(c != 0): %d\n", c != 0);  // 1 -> 真

    // 比較演算の結果も0/1
    printf("3 < 5: %d\n", 3 < 5);
    printf("3 > 5: %d\n", 3 > 5);
    printf("3 == 3: %d\n", 3 == 3);
    printf("3 != 3: %d\n", 3 != 3);
    return 0;
}
実行結果
a を条件にした評価(a != 0): 0
b を条件にした評価(b != 0): 1
c を条件にした評価(c != 0): 1
3 < 5: 1
3 > 5: 0
3 == 3: 1
3 != 3: 0

論理演算の結果や比較演算の結果が整数であるという点は、printf("%d", 条件)などで確認するのに便利です。

if文での条件の評価

ifは括弧内の式が0以外なら真、0なら偽として分岐します。

変数をそのまま条件に使うこともできます。

C言語
// if文における0/非0の評価
#include <stdio.h>

int main(void) {
    int x = 0;

    if (x) {
        printf("if(x): xは真です\n");
    } else {
        printf("if(x): xは偽です\n");
    }

    x = -5;
    if (x != 0) {  // 明示的に比較しても同じ意味
        printf("if(x != 0): xは非0なので真です\n");
    }
    return 0;
}
実行結果
if(x): xは偽です
if(x != 0): xは非0なので真です

比較演算子(>, <, ==, !=)の使い方

>(大なり)と<(小なり)の基本

><は大小関係を判定します。

結果は0または1です。

C言語
// > と < の基本
#include <stdio.h>

int main(void) {
    int x = 7;
    int y = 10;

    printf("x(7) > y(10): %d\n", x > y);
    printf("x(7) < y(10): %d\n", x < y);
    return 0;
}
実行結果
x(7) > y(10): 0
x(7) < y(10): 1

==(等しい)と!=(等しくない)

==は等値比較、!=は不等比較です。

文字や整数だけでなく浮動小数点数にも使えますが、浮動小数点では丸め誤差に注意が必要です。

C言語
// == と != の基本、浮動小数点の注意点
#include <stdio.h>
#include <math.h>

int main(void) {
    int p = 5, q = 5, r = 6;
    printf("p == q: %d\n", p == q); // 1
    printf("p != r: %d\n", p != r); // 1

    double a = 0.1 + 0.2;
    double b = 0.3;
    printf("a == b (0.1+0.2 と 0.3 の比較): %d\n", a == b); // 多くの環境で 0
    // 誤差を考慮した比較の例(許容誤差を設ける)
    double eps = 1e-9;
    printf("|a-b| < eps による近似比較: %d\n", fabs(a - b) < eps);
    return 0;
}
実行結果
p == q: 1
p != r: 1
a == b (0.1+0.2 と 0.3 の比較): 0
|a-b| < eps による近似比較: 1

文字列リテラル同士を==で比較するとポインタ比較になります

文字列の内容を比較する場合はstrcmpを使うべきですが、これは別の記事で扱います。

= と == の違いに注意

=は代入、==は比較です。

ifの条件で代入してしまうミスは非常に多いです。

C言語
// 悪い例: ifの中で=を使ってしまう(代入になり、式全体の値が条件になる)
#include <stdio.h>

int main(void) {
    int n = 0;

    if (n = 0) {   // ここは「nが0に代入され、その結果0が条件」となる -> 偽
        printf("n = 0 の if: 真\n");
    } else {
        printf("n = 0 の if: 偽(elseが実行)\n");
    }

    if (n = 1) {   // 「nが1に代入され、その結果1が条件」となる -> 真
        printf("n = 1 の if: 真(ifが実行)\n");
    } else {
        printf("n = 1 の if: 偽\n");
    }
    return 0;
}
実行結果
n = 0 の if: 偽(elseが実行)
n = 1 の if: 真(ifが実行)
C言語
// 良い例: == を使う、さらに()で意図を明確にする
#include <stdio.h>

int main(void) {
    int n = 0;

    if (n == 0) {
        printf("n == 0: 真\n");
    } else {
        printf("n == 0: 偽\n");
    }
    return 0;
}
実行結果
n == 0: 真

コンパイラの警告(-Wallなど)を有効にしておくと、代入の取り違えを早期に検出しやすくなります

論理演算子(&&, ||, !)の使い方

&&(かつ)の基本

&&は両方の条件が真のとき真になります。

たとえば「20代か」を判定する場合は次のように書けます。

C言語
// && の基本: 範囲判定の例(20 <= age < 30 相当)
#include <stdio.h>

int main(void) {
    int age = 25;
    int is_twenty代 = (age > 19) && (age < 30); // >, < のみで書く
    printf("age=%d は20代か: %d\n", age, is_twenty代);
    return 0;
}
実行結果
age=25 は20代か: 1

||(または)の基本

||はどちらか一方でも真なら真になります。

C言語
// || の基本: 複数学値のいずれかに該当
#include <stdio.h>

int main(void) {
    char grade = 'B';
    int is_pass = (grade == 'A') || (grade == 'B');
    printf("grade=%c は合格ランク(AまたはB)か: %d\n", grade, is_pass);
    return 0;
}
実行結果
grade=B は合格ランク(AまたはB)か: 1

!(否定)の基本

!は真偽を反転します。

!01!非00です。

C言語
// ! の基本
#include <stdio.h>

int main(void) {
    printf("!0: %d\n", !0);
    printf("!5: %d\n", !5);
    int n = 0;
    if (!n) {
        printf("nは0なので!nは真\n");
    }
    return 0;
}
実行結果
!0: 1
!5: 0
nは0なので!nは真

短絡評価(ショートサーキット)の基本

&&||は必要のない側を評価しません

これを短絡評価と呼びます。

&&は左が偽なら右を評価せずに偽、||は左が真なら右を評価せずに真になります。

C言語
// 短絡評価の観察: どちらの式が評価されたかを表示する
#include <stdio.h>

int log_and_return(const char *label, int value) {
    printf("%s が評価されました(value=%d)\n", label, value);
    return value;
}

int main(void) {
    int a = 0, b = 1;

    // 左が偽(0)なので右は評価されない
    int r1 = log_and_return("左辺(AND)", a) && log_and_return("右辺(AND)", b);
    printf("結果 a && b: %d\n", r1);

    // 左が真(非0)なので右は評価されない
    int r2 = log_and_return("左辺(OR)", b) || log_and_return("右辺(OR)", a);
    printf("結果 b || a: %d\n", r2);

    return 0;
}
実行結果
左辺(AND) が評価されました(value=0)
結果 a && b: 0
左辺(OR) が評価されました(value=1)
結果 b || a: 1

副作用のある関数呼び出しや代入を条件式の右側に置くと、短絡評価のために実行されないことがあります

条件式は「評価されなくても良い」設計にするのが安全です。

比較演算子との組み合わせ例

複合条件は括弧で区切ると読みやすくなります。

合格基準を「点数が70より大きく欠席が3未満、または満点」とする例です。

C言語
// 比較と論理の組み合わせ
#include <stdio.h>

int main(void) {
    int score = 75;
    int absence = 2;

    int pass = ((score > 69) && (absence < 3)) || (score == 100);
    printf("score=%d, absence=%d -> pass: %d\n", score, absence, pass);
    return 0;
}
実行結果
score=75, absence=2 -> pass: 1

if, whileでの活用

whileで配列を先頭から走査し、0が現れたら止める例です。

短絡評価により「範囲内か」を先に判定することで、安全にアクセスできます。

C言語
// whileで条件を組み合わせて安全に走査する
#include <stdio.h>

int main(void) {
    int data[] = {5, 3, 0, 7, 9};
    int n = (int)(sizeof(data) / sizeof(data[0]));
    int i = 0;

    // i < n が偽になった時点で右側は評価されない(短絡評価)
    while ((i < n) && (data[i] != 0)) {
        printf("data[%d] = %d\n", i, data[i]);
        i++;
    }

    if ((i < n) && (data[i] == 0)) {
        printf("最初の0をdata[%d]で検出\n", i);
    }
    return 0;
}
実行結果
data[0] = 5
data[1] = 3
最初の0をdata[2]で検出

よくあるミスとコツ(初心者向け)

比較は論理より先に評価(優先順位)

C言語では、!、比較(<==など)、&&||の順に優先順位があります

つまりa < b && b < c(a < b) && (b < c)と解釈されます。

曖昧さを避けるため括弧で明示すると読みやすくなります。

以下は優先順位の目安です(高い→低い)。

優先度演算子(一部)意味
!否定
<, >, <=, >=大小比較
==, !=等値比較
&&論理積
||論理和
C言語
// 優先順位による違いの例
#include <stdio.h>

int main(void) {
    int a = 0, b = 1, c = 2;

    int r1 = a == b || c;         // (a == b) || c と解釈 -> 0 || 2(真) -> 真(1)
    int r2 = a == (b || c);       // (b || c) は真(1) -> a == 1 -> 偽(0)

    printf("r1: %d, r2: %d\n", r1, r2);
    return 0;
}
実行結果
r1: 1, r2: 0

意図が伝わる括弧づけは、バグの予防にも大きく役立ちます。

カッコ()で意図を明確に

演算子の優先順位に頼らず、論理ブロックは括弧でまとめると、将来の修正やレビュー時の誤解を避けられます。

C言語
// 括弧で論理ブロックを明示
#include <stdio.h>

int main(void) {
    int x = 8;
    int in_range = (x > 0) && (x < 10); // どちらの比較が && の左右なのか一目瞭然
    printf("0 < x && x < 10: %d\n", in_range);
    return 0;
}
実行結果
0 < x && x < 10: 1

0/非0とtrue/falseの混同に注意

論理演算や比較の結果は0か1に正規化されますが、ifの条件としては「非0なら真」です。

したがってif (flag == 1)と書くと、flag2などの非0でも偽になってしまいます。

C言語
// 0/非0と1の違い
#include <stdio.h>

int main(void) {
    int flag = 2;

    printf("flag を条件(非0)として評価: %d\n", flag != 0); // 1
    printf("flag == 1 と等値比較: %d\n", flag == 1);       // 0

    // 論理演算の結果は常に0/1
    printf("5 && 2: %d\n", 5 && 2); // 1
    printf("5 || 0: %d\n", 5 || 0); // 1
    return 0;
}
実行結果
flag を条件(非0)として評価: 1
flag == 1 と等値比較: 0
5 && 2: 1
5 || 0: 1

「真かどうか」を見たいときはif (flag)のように書くのがC言語の慣習です。

true/falseを使うならstdbool.h

C99以降ではstdbool.hbooltruefalseが使えます。

内部的には0/1の整数なので、printfでは%dで出力できます。

C言語
// stdbool.h の利用
#include <stdio.h>
#include <stdbool.h>

int main(void) {
    bool ok = true;
    bool ng = false;

    printf("ok=%d, ng=%d\n", ok, ng);

    int n = 2;
    bool b = n; // 非0を代入するとtrue(1)になる
    printf("n=2 を bool に代入 -> b=%d\n", b);

    if (!ng && ok) {
        printf("!ng && ok は真です\n");
    }
    return 0;
}
実行結果
ok=1, ng=0
n=2 を bool に代入 -> b=1
!ng && ok は真です

参考: 真理値表(0/1で表記)

論理演算子の基本的な真理値は次の通りです。

入力は0を偽、1を真として示しています。

ABA&&BA||B!A
00001
01011
10010
11110

実際のコードでは「非0は真」ですが、論理演算の結果は0か1に正規化されます。

まとめ

比較演算子と論理演算子は、条件分岐やループの表現力を支える基本要素です。

Cでは0が偽、非0が真であり、比較や論理演算の結果は整数の0/1になります。

= と == の取り違え短絡評価による未評価優先順位の誤解は初学者がつまずきやすいポイントです。

常に括弧で意図を明確にし、-Wallなどの警告を活用し、必要に応じてstdbool.hboolを使うことで、読みやすく安全なコードになります。

今回学んだ><==!=&&||!を使いこなし、条件表現を着実に身につけていきましょう。

この記事を書いた人
エーテリア編集部
エーテリア編集部

プログラミングの基礎をしっかり学びたい方向けに、C言語の基本文法から解説しています。ポインタやメモリ管理も少しずつ理解できるよう工夫しています。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!