C言語のif文は、プログラムに「条件によって処理を分ける」という考え方を教えてくれる、とても重要な構文です。
本記事では、if文の基本構造から、条件式の書き方、よくあるミス、そして実践的なコツまでを、図解とサンプルコードを交えながら丁寧に解説します。
C言語初心者の方でも、読み終える頃には自信を持ってif文を書けるようになることを目指します。
C言語のif文とは
if文の基本構造
if文は「条件が成り立つかどうかを判定して、成り立つ場合だけ処理を実行する」ための構文です。
C言語での基本的な形は次のようになります。
if (条件式) {
/* 条件式が真(true)のときに実行される処理 */
}
ここで重要なのは、条件式の評価結果が「0か0以外か」で真偽が決まるという点です。
C言語では、0は偽(false)、0以外は真(true)として扱われます。

最小のif文サンプル
#include <stdio.h>
int main(void) {
int x = 10;
/* xが5より大きければメッセージを表示する */
if (x > 5) {
printf("xは5より大きいです。\n");
}
printf("プログラムを終了します。\n");
return 0;
}
xは5より大きいです。
プログラムを終了します。
この例では、x > 5 が真なので、if文のブロック内のprintfが実行されます。
条件分岐の流れと実行順序
if文の処理の流れを、実行順に整理します。

if文は次の手順で処理されます。
- プログラムは上から順番に命令を実行します。
- if文に到達すると、かっこ
()内の条件式が評価されます。 - 条件式の結果が0以外なら、ブロック
{ }内の処理を先頭から順に実行します。 - 条件式の結果が0なら、ブロック内をすべて飛ばして、if文の直後の文から実行を再開します。
この「上から順に実行し、条件のところで分岐する」という流れをイメージできると、後で出てくるelseやelse ifも理解しやすくなります。
if文でできること・できないこと
if文には明確な役割があります。
ここでは、できることとできないことを整理します。

代表的なポイントを文章で整理すると次のようになります。
if文でできることとしては、まず最も基本的に、条件に応じて異なる処理を行うことが挙げられます。
例えば、点数に応じて評価を表示したり、ログインの成功・失敗でメッセージを変えたりといった処理は、すべてif文で表現できます。
また、比較演算子や論理演算子を用いて複雑な条件式を作り、複数の条件を組み合わせた分岐も可能です。
一方で、if文だけではできないこともあります。
代表的なものとして、同じ処理を何度も繰り返すループ処理が挙げられます。
繰り返しはfor文やwhile文の役割です。
また、#ifのようなプリプロセッサディレクティブと違い、コンパイル時にコードそのものを削除したり追加したりすることもできません。
if文はあくまで実行時に「どの処理を動かすか」を選ぶ仕組みです。
if文の書き方と条件式の基礎
比較演算子(==, !=, > など)の使い方
if文で条件を表現するとき、比較演算子は欠かせません。
代表的な比較演算子と意味を、まず表で整理します。

| 演算子 | 読み方 | 意味 | 例 | 結果 |
|---|---|---|---|---|
| == | イコール | 左右が等しい | x == 5 | xが5なら真 |
| != | ノットイコール | 左右が等しくない | x != 0 | xが0以外で真 |
| > | 大なり | 左が右より大きい | x > 10 | 11なら真 |
| < | 小なり | 左が右より小さい | x < 0 | -1なら真 |
| >= | 以上 | 左が右以上(大きいか等しい) | x >= 60 | 60,70で真 |
| <= | 以下 | 左が右以下(小さいか等しい) | x <= 100 | 100,90で真 |

比較演算子を使った基本例
#include <stdio.h>
int main(void) {
int score = 75;
/* scoreが60以上なら合格と表示する */
if (score >= 60) {
printf("合格です。\n");
}
/* scoreが100と等しいかどうかを比較する */
if (score == 100) {
printf("満点です。\n");
}
/* scoreが0でないことを確認する */
if (score != 0) {
printf("スコアは0ではありません。\n");
}
return 0;
}
合格です。
スコアは0ではありません。
このように、比較演算子の結果は「真か偽」になり、そのままif文の条件式として使えると理解してください。
論理演算子(&&, ||, !)で条件を組み合わせる
現実の条件は「AかつB」「AまたはB」「Aではない」という形になることが多くあります。
C言語では、論理演算子を使って複数の条件を組み合わせます。

| 演算子 | 読み方 | 意味 | 例 |
|---|---|---|---|
| && | かつ(AND) | 両方の条件が真なら真 | x > 0 && x < 10 |
| || | または(OR) | どちらか一方でも真なら真 | x < 0 || x > 100 |
| ! | 否定(NOT) | 条件が真なら偽、偽なら真に反転する | !(x == 0) は x != 0 と同じ意味 |
論理演算子のサンプル
#include <stdio.h>
int main(void) {
int age = 20;
int has_ticket = 1; /* 1は「持っている」、0は「持っていない」とする */
/* 18歳以上 かつ チケットを持っている場合に入場可能とする */
if (age >= 18 && has_ticket == 1) {
printf("入場できます。\n");
}
/* 13歳未満 または 60歳以上なら割引対象とする */
if (age < 13 || age >= 60) {
printf("割引対象です。\n");
}
/* チケットを持っていない場合のみ表示 */
if (!has_ticket) {
printf("チケットを購入してください。\n");
}
return 0;
}
入場できます。
この例では論理演算子を使うことで、1つのif文に複数条件をまとめて書けることが分かります。
「かつ」は&&、「または」は||、「〜ではない」は!と覚えておくとよいです。
if〜else, else ifの書き方と使い分け
現実の処理では、「〜ならA、そうでなければB」といった2者択一や、「条件によって3通り以上に分岐」したい場面も多くあります。
そのときに使うのがelseとelse ifです。

if〜elseの基本形
#include <stdio.h>
int main(void) {
int x = -5;
if (x >= 0) {
printf("xは0以上です。\n");
} else {
printf("xは負の値です。\n");
}
return 0;
}
xは負の値です。
ifの条件が偽のときに必ず実行したい処理がある場合にelseを使います。
else ifで3通り以上に分岐する
#include <stdio.h>
int main(void) {
int score = 72;
if (score >= 80) {
printf("評価: A\n");
} else if (score >= 60) {
printf("評価: B\n");
} else if (score >= 40) {
printf("評価: C\n");
} else {
printf("評価: D\n");
}
return 0;
}
評価: B
ここでのポイントは、上から順に条件が評価され、どれか1つが真になった時点で残りはチェックされないということです。
つまり、排他的な条件分岐を簡潔に表現できる仕組みになっています。
ブロック({})とインデントの書き方
if文では{ }で囲まれた部分をブロックと呼びます。
ブロックの中身は原則としてインデント(字下げ)して書くことで、どこからどこまでが条件付きの処理かを分かりやすくします。

ブロックとインデントの例
#include <stdio.h>
int main(void) {
int x = 10;
if (x > 0) {
/* ここからif文のブロック */
printf("xは正の数です。\n");
printf("xの値は%dです。\n", x);
/* ここまでがif文のブロック */
}
printf("この行は条件に関係なく実行されます。\n");
return 0;
}
xは正の数です。
xの値は10です。
この行は条件に関係なく実行されます。
ブロック内に1行しか処理がない場合でも、次のように{ }をつけた書き方をおすすめします。
if (x > 0) {
printf("xは正です。\n");
}
C言語では{ }を省略して1行だけ書くことも可能ですが、後から行を追加したときのバグの原因になりやすいため、常にブロックをつける書き方を習慣にした方が安全です。
C言語if文でよくあるミスと注意点
‘=’と’==’の書き間違いを防ぐポイント
C言語のif文で最も多いミスの1つが、代入演算子=と比較演算子==の書き間違いです。

よくある誤りの例
#include <stdio.h>
int main(void) {
int x = 3;
/* 間違い: x == 5 と書くべきところを x = 5 と書いてしまった */
if (x = 5) {
printf("xは5です。\n");
} else {
printf("xは5ではありません。\n");
}
printf("xの最終的な値は%dです。\n", x);
return 0;
}
xは5です。
xの最終的な値は5です。
このコードは一見「xが5かどうか判定している」ように見えますが、実際にはx = 5でxに5を代入しています。
代入式x = 5の評価結果は5であり、0以外なので常に真になってしまいます。
そのため、if文は必ず真になり、xは毎回5に書き換えられるという危険なバグになります。
防ぐためのコツ
このミスを防ぐためのポイントを文章で挙げます。
まず、ifの条件では「==」を使うという意識を常に持つことが大切です。
特に、値と比較するときはif (x == 5)と書く習慣を徹底してください。
また、コンパイラの警告を有効にすることも非常に有効です。
多くのコンパイラは、条件式の中で代入を行っていると警告を出してくれます。
例えばgccであれば-Wallオプションを付けてコンパイルすることで、こういったミスの多くを自動的に検出できます。
セミコロン(;)の付け忘れ・付けすぎによるバグ
C言語では文の終わりに必ずセミコロン;が必要です。
ただし、if文ではセミコロンの位置がとても重要です。

単純な付けすぎの例
#include <stdio.h>
int main(void) {
int x = 10;
/* 間違い: if文の直後にセミコロンを書いてしまった */
if (x > 0); {
printf("xは正の数です。\n");
}
return 0;
}
xは正の数です。
このコードは一見正しく見えますが、if (x > 0); という1つの文がここで終わっており、その後の{ }はifとは無関係な単なるブロックになっています。
その結果、条件に関係なく常にprintfが実行されるというバグになります。
if文のかっこ()の直後にはセミコロンを書かないというルールを覚えておくと良いです。
一方、printfなどの通常の文の末尾には必ずセミコロンが必要です。
セミコロンの「付け忘れ」はコンパイルエラーになることが多く、コンパイラが場所を教えてくれるので、エラー文をよく読みながら修正してください。
条件式が常に真(true)または偽(false)になる落とし穴
if文の条件式が、書いた人の意図に反して常に真または常に偽になってしまうケースもよくあります。

代表的な例1: 連鎖比較の誤用
#include <stdio.h>
int main(void) {
int x = 50;
/* 間違い: Cではこの書き方は範囲チェックにならない */
if (0 <= x <= 100) {
printf("xは0〜100の範囲内です。\n");
} else {
printf("xは範囲外です。\n");
}
return 0;
}
xは0〜100の範囲内です。
C言語では0 <= x <= 100という書き方は、(0 <= x) <= 100と解釈されます。
(0 <= x)は真なら1、偽なら0になります。
その結果、1 <= 100または0 <= 100という比較になり、どちらにしても常に真になってしまいます。
範囲チェックをしたいときは、必ず0 <= x && x <= 100のように論理演算子と組み合わせて書く必要があります。
代表的な例2: 代入ミスによる常に真
先ほど触れたif (x = 5)のような代入ミスも、条件が常に真になる典型例です。
どちらの場合も、コンパイラ警告の活用とコードレビューが有効な対策になります。
浮動小数点の比較で起きやすい誤判定
C言語では浮動小数点型(float, double)の比較に注意が必要です。
見た目は同じ値でも、内部表現の誤差により完全に等しくならないことがよくあります。

浮動小数点比較の罠
#include <stdio.h>
int main(void) {
double a = 0.1 * 3; /* 0.3のつもり */
double b = 0.3;
if (a == b) {
printf("aとbは等しいです。\n");
} else {
printf("aとbは等しくありません。\n");
}
/* 実際の値を表示してみる */
printf("a = %.17f\n", a);
printf("b = %.17f\n", b);
return 0;
}
aとbは等しくありません。
a = 0.30000000000000004
b = 0.29999999999999999
このように、double同士を==で比較すると、意図しない偽が返ることがあります。
安全な比較方法(許容誤差を使う)
浮動小数点を比較するときは、「差が十分に小さいかどうか」を見る方法がよく使われます。
#include <stdio.h>
#include <math.h>
int main(void) {
double a = 0.1 * 3;
double b = 0.3;
double eps = 1e-9; /* 許容する誤差 */
if (fabs(a - b) < eps) {
printf("aとbはほぼ等しいとみなします。\n");
} else {
printf("aとbは異なる値とみなします。\n");
}
return 0;
}
aとbはほぼ等しいとみなします。
このように、浮動小数点では「完全一致」を前提にしないことが重要です。
論理演算子とビット演算子(&&, & など)の混同
C言語には論理演算子&&, ||とビット演算子&, |があり、記号が似ているために書き間違いや誤解を招きがちです。

間違いやすいコード例
#include <stdio.h>
int main(void) {
int x = 5;
int y = 10;
/* 間違い: && のつもりで & を書いてしまった */
if (x > 0 & y > 0) {
printf("xとyはともに正です。\n");
}
return 0;
}
このコードは、xとyがともに正のときに真になるようにも見えますが、実際にはx > 0とy > 0がビット演算で&されているだけです。
多くの場合はたまたま期待通りに動きますが、短絡評価(short-circuit)が行われないなどの違いがあり、バグの原因になります。
正しい使い分け
論理演算子とビット演算子の違いを簡単にまとめると次のようになります。
| 種類 | 演算子 | 対象 | 用途 |
|---|---|---|---|
| 論理演算子 | &&, || | 真偽値(条件) | ifの条件を組み合わせる |
| ビット演算子 | &, | | 整数の各ビット | ビットフラグ、マスク処理など |
if文の条件式で「かつ」「または」を表現したいときは、必ず&&と||を使うようにしてください。
C言語if文を使いこなすコツ
ネストしたif文をシンプルに書くテクニック
条件分岐が増えると、if文の中にif文を書くネストが発生しがちです。
ネストが深くなると、コードが読みにくく、バグも混入しやすくなります。

ネストが深い例
#include <stdio.h>
int main(void) {
int age = 20;
int has_id = 1; /* 身分証(1:あり, 0:なし) */
if (age >= 18) {
if (has_id) {
printf("入場できます。\n");
} else {
printf("身分証を提示してください。\n");
}
} else {
printf("18歳未満は入場できません。\n");
}
return 0;
}
この程度ならまだ読めますが、条件が増えてくると、どの}がどのifに対応しているのか分かりにくくなります。
ネストを浅くする書き方(早期リターン)
関数の中であれば、条件を満たさない場合に早めにreturnしてしまうことで、if文をフラットにできます。
#include <stdio.h>
void check_entry(int age, int has_id) {
if (age < 18) {
printf("18歳未満は入場できません。\n");
return; /* ここで関数を終える */
}
if (!has_id) {
printf("身分証を提示してください。\n");
return;
}
printf("入場できます。\n");
}
int main(void) {
check_entry(20, 1);
return 0;
}
入場できます。
このように、「ダメなケース」を先に処理して抜けるスタイルを採用すると、if文の入れ子を減らして読みやすいコードにできます。
条件式を読みやすくするリファクタリング
if文の条件式が長くなってくると、「何を判定しているのか」が分かりにくくなります。
そこで、条件式を整理(リファクタリング)することが重要になります。

そのままだと読みにくい例
#include <stdio.h>
int main(void) {
int age = 25;
int is_member = 1;
int is_holiday = 0;
int has_coupon = 1;
if (age >= 18 && (is_member || has_coupon) && !is_holiday) {
printf("割引を適用できます。\n");
}
return 0;
}
この条件式は、1行で書くと何を判定しているのか直感的に分かりづらくなります。
意味のある名前をつけて整理する
#include <stdio.h>
int main(void) {
int age = 25;
int is_member = 1;
int is_holiday = 0;
int has_coupon = 1;
int is_adult = (age >= 18);
int can_get_benefit = (is_member || has_coupon);
int is_business_day = !is_holiday;
if (is_adult && can_get_benefit && is_business_day) {
printf("割引を適用できます。\n");
}
return 0;
}
割引を適用できます。
このように中間の条件に名前をつけることで、if文が「日本語の文章」に近い読みやすさになります。
特に業務ロジックのような複雑な条件分岐では、この手法が有効です。
デバッグでif文の動作を確認する方法
if文が意図どおりに動いているか不安なときは、デバッグが必要です。
ここでは、C言語でよく使われる2つの方法を紹介します。

1. printfを使ったデバッグ
最も手軽な方法は、if文の前後にprintfで値を表示することです。
#include <stdio.h>
int main(void) {
int score = 58;
printf("デバッグ: score = %d\n", score);
if (score >= 60) {
printf("合格です。\n");
} else {
printf("不合格です。\n");
}
return 0;
}
デバッグ: score = 58
不合格です。
このように条件に使う変数の値を出力しておくことで、「このときscoreはいくつだったのか」「なぜこの分岐に入ったのか」が分かりやすくなります。
2. デバッガを使ってステップ実行する
もう一歩進んだ方法として、デバッガを使って1行ずつ実行を追いかけるやり方があります。
例えばgdbや、Visual Studio Code、CLionなどのIDEに内蔵されたデバッガを利用すると、次のようなことができます。
まず、if文の行にブレークポイントを置き、プログラムをデバッグ実行します。
プログラムがその行で一時停止したら、変数の値をウォッチしながら条件式がどう評価されるかを確認できます。
さらに、ステップインやステップオーバーを使って、実際にどちらのブロックに入ったかを目で追うことができます。
この方法は最初は少しハードルが高く感じるかもしれませんが、慣れるとバグ調査の強力な武器になります。
if文に限らず、プログラム全体の理解にも役立ちます。
まとめ
本記事では、C言語のif文について、基本構造・条件式の書き方・よくあるミス・使いこなしのコツまでを一通り解説しました。
特に「0は偽、0以外は真」「==と=の違い」「論理演算子とビット演算子の区別」は、if文を正しく使ううえで非常に重要なポイントです。
実際に手を動かしてサンプルコードを書き換えながら学ぶことで、条件分岐の感覚が身につきます。
ぜひ、さまざまな条件やパターンを試しながら、if文を自在に扱えるようになってください。
