C言語で条件に応じて処理を切り替えるにはif文を正しく書くことが鍵です。
この記事では基本のifからif-else、else ifまでを順に解説し、{ }や0/非0の真偽の扱い、よくあるミスと防ぎ方も網羅します。
最後には練習課題も用意し、段階的に理解を固めます。
C言語のif文: 基本の使い方と書き方
if文は条件式が真か偽かで、実行する文(ブロック)を選ぶ構文です。
Cでは0は偽、0以外は真という評価規則で動作します。
if(条件式)の構文
最小構成のif文は1つの条件式と、その条件が真のときに実行する文から成ります。
実務では可読性と安全性のため、原則としてブロックを{ }で囲む書き方を推奨します。
- 基本形は
if (条件式) 文;
またはif (条件式) { /* 文の並び */ }
です。 - 条件式は
int
などの整数値に評価され、0が偽、非0が真です。 - 比較には
==
や!=
などを使います(詳細は別記事で扱います)。
条件式の丸括弧( )は必須です。
if x == 0
のように括弧を省略してはいけません。
0と非0の真偽判定
Cではbool型がなくても、整数の0/非0で真偽を表現できます(stdbool.hを使う方法もありますが、本稿では0/非0で説明します)。
以下は、代表的な値がifでどう評価されるかの一覧です。
値 | 真偽の評価 | 例 |
---|---|---|
0 | 偽(false) | if (0) {/* 実行されない */} |
1, -1, 2, … | 真(true) | if (42) {/* 実行される */} |
変数xが0 | 偽 | int x=0; if (x) {/* 実行されない */} |
変数xが非0 | 真 | int x=5; if (x) {/* 実行される */} |
比較演算の結果(例: a == b
)は0または1になります。
したがってifの条件式には比較式を置くのが一般的です。
ブロックと{ }のルール
1文だけなら{ }を省略できますが、バグ防止と将来の拡張のため常に{ }を付ける習慣を推奨します。
特にインデントと実際の制御範囲がズレる事故を避けられます。
if (cond) do_something();
は合法ですが危険です。if (cond) { do_something(); do_more(); }
とすれば安心です。- 「ぶら下がりelse(dangling else)」問題を避けるためにも、
if
とelse
のペアを{ }で明示します。
サンプルコード(基本のif)
偶数判定の最小例です。
剰余演算子%
を使って2で割った余りが0かどうかを調べます。
#include <stdio.h>
int main(void) {
int x = 10;
// x を 2 で割った余りが 0 なら偶数
if (x % 2 == 0) { // 条件式が真のとき
printf("%d は偶数です\n", x); // このブロックが実行される
}
// ここは if の外なので常に実行
printf("チェック完了\n");
return 0;
}
10 は偶数です
チェック完了
x % 2 == 0
は0/1に評価され、ifはそれを真偽として解釈します。
if-elseで2択の条件分岐
if-elseは「AならX、そうでなければY」という二者択一の構文です。
どちらか一方だけが必ず実行されます。
elseの書き方
elseは直前のifに必ず結び付きます。
else
の後ろも1文または{ }のブロックです。
- 書式:
if (条件) { 真の処理 } else { 偽の処理 }
- if部が実行されなかった場合にのみelse部が実行されます。
実行フローの流れ
評価は常にifの条件式から始まり、真ならifブロック、偽ならelseブロックへ直行します。
その後は共通の後続処理へ合流します。
不要なネストを避け、分岐ごとにやるべき作業を明確に保ちます。
サンプルコード(if-else)
奇数/偶数を分けてメッセージを変える例です。
#include <stdio.h>
int main(void) {
int x = 7;
if (x % 2 == 0) {
printf("%d は偶数です\n", x);
} else {
printf("%d は奇数です\n", x);
}
printf("判定終了\n");
return 0;
}
7 は奇数です
判定終了
if側とelse側のどちらか一方だけが実行され、両方が実行されることはありません。
else ifで複数条件を判定
else ifを連ねると「最初に条件を満たしたひとつだけ」を選択できます。
範囲チェックなどに有用です。
else ifの読み順と優先度
上から順に評価し、最初に真になった分岐のブロックだけが実行されます。
以降の分岐はスキップされます。
したがってより限定的(厳しい)な条件を先に書くのが安全です。
範囲チェックのコツ(例: 点数)
範囲が被らないように不等号の向きと境界をそろえることが大事です。
例えば点数0〜100点なら、上位から>=
で落としていくと漏れが起きにくくなります。
- 例:
score >= 90
、次にscore >= 70
、次にscore >= 50
、最後にそれ以外
最後のelse(デフォルト処理)
すべての条件が偽だった場合の保険として最後にelseを置くと、安全な既定値やエラーメッセージを出せます。
想定外の値に備える意味でも有効です。
条件の重なりに注意
条件が重なると上に書いた方が常に選ばれてしまうため、下の分岐が実行されません。
例えばscore >= 50
を先に書くとscore >= 90
が到達不能になります。
より狭い条件を先に書きましょう。
サンプルコード(else if)
点数から成績を判定する例です。
境界を含む順序に注意して並べます。
#include <stdio.h>
// 成績を文字で返す関数(0/非0の真偽を使わず、文字で返す例)
char grade_from_score(int score) {
if (score >= 90) { // 90〜100
return 'A';
} else if (score >= 70) { // 70〜89
return 'B';
} else if (score >= 50) { // 50〜69
return 'C';
} else { // 0〜49 それ以外は不合格
return 'D';
}
}
int main(void) {
int score = 83;
char g = grade_from_score(score);
printf("score=%d, grade=%c\n", score, g);
return 0;
}
score=83, grade=B
いずれか1つのブロックだけが実行されるため、メッセージの多重出力は起きません。
初心者がつまずくif文のミスとベストプラクティス
よくある落とし穴を知っておくと、短時間でバグの芽を摘めます。
合わせて避け方のコツも示します。
=(代入)と==(比較)の取り違え
=
は代入、==
は比較です。
代入式は代入後の値(右辺の値)に評価されるため、意図せず「常に真/偽」になる事故が起きます。
#include <stdio.h>
int main(void) {
int x = 0;
// 悪い例: 代入してしまっている。if (x = 1) は x に 1 を代入し、その結果(1)が評価され真になる
if (x = 1) {
printf("常に真(バグ)\n");
}
// 良い例: 比較演算子 == を使う
if (x == 1) {
printf("x は 1 です\n");
}
return 0;
}
常に真(バグ)
x は 1 です
コンパイラ警告を最大化(例: -Wall -Wextra -Werror
)し、コードレビューで==
の有無を確認します。
ifの直後の;(セミコロン)に注意
ifの直後にセミコロンを書くと「空文」を条件付きで実行してしまうため、ブロックが常に実行されるバグになります。
#include <stdio.h>
int main(void) {
int x = 0;
if (x == 0); { // ← ここにセミコロンがあると、この if は「何もしない」
printf("常に実行される(バグ)\n");
}
// 正しい書き方
if (x == 0) {
printf("条件が真のときだけ実行\n");
}
return 0;
}
常に実行される(バグ)
条件が真のときだけ実行
ifの行末に不要な;がないか必ず目視し、{ を同じ行に置くコーディング規約で防止します。
{ }省略の危険とインデント
見た目のインデントにだまされないことが重要です。
{ }を省略すると「1文だけ」がifの対象になります。
#include <stdio.h>
int main(void) {
int cond = 0;
// 悪い例: 2行目の printf は if の外。インデントにだまされる
if (cond)
printf("条件が真\n");
printf("いつでも表示(バグ)\n");
// 良い例: 必ず { } を付ける
if (cond) {
printf("条件が真\n");
printf("この2行はまとめて条件付き\n");
}
return 0;
}
いつでも表示(バグ)
単文でも{ }を付ける。
自動整形ツール(例: clang-format)の利用も有効です。
ネストを浅くする(早期return)
早期returnでガード条件を先に処理すると、ネストが浅くなり読みやすくなります。
#include <stdio.h>
void process(int *p, int size) {
// 悪い例: ネストが深い
if (p != NULL) {
if (size > 0) {
printf("処理中...\n");
}
}
// 良い例: 早期に異常系を返す
if (p == NULL) return;
if (size <= 0) return;
printf("処理完了...\n");
}
int main(void) {
process(NULL, 10); // 何もせず戻る
process((int[]){1, 2, 3}, 3); // 正常パス
return 0;
}
処理中...
処理完了...
条件分岐の入れ子を減らして意図を明確化できます。
条件は関数に切り出す
複雑な条件は関数名に意味を込めて切り出すと、本体のifが読みやすくなります。
#include <stdio.h>
// 非0: 合格、0: 不合格
int is_passing(int score) {
// 条件の意味を関数名に反映
return score >= 60;
}
int main(void) {
int score = 58;
if (is_passing(score)) {
printf("合格\n");
} else {
printf("不合格\n");
}
return 0;
}
不合格
テスト容易性と再利用性が向上し、条件の重複も避けられます。
デバッグ出力で条件を確認(printf)
条件が意図通りか自信がないときは、判定直前に値を出力して確認します。
#include <stdio.h>
int main(void) {
int a = 3, b = 5;
printf("[DEBUG] a=%d, b=%d, a<b=%d\n", a, b, a < b); // 条件式の評価も出す
if (a < b) {
printf("a は b より小さい\n");
} else {
printf("a は b 以上\n");
}
return 0;
}
[DEBUG] a=%d, b=%d, a<b=%d
[DEBUG] a=3, b=5, a<b=1
a は b より小さい
比較式の評価値(0/1)も出すと真偽の取り扱いを誤解しにくくなります。
練習課題で定着
小さなプログラムを自分で書くのが最短の上達法です。
次の課題で確認しましょう。
- 整数nが3の倍数なら「Fizz」、5の倍数なら「Buzz」、両方の倍数なら「FizzBuzz」、どれでもなければnを表示するプログラムを作成してください。
- 体温(小数)を入力し、37.5以上なら「発熱」、36.0以上37.5未満なら「平熱」、36.0未満なら「低体温」と表示してください。
- 年齢を入力し、0〜12で「子ども」、13〜19で「ティーン」、20以上で「大人」、負の値や極端な値は「不正な入力」と表示してください(最後のelseを活用)。
境界条件の順序と重なりに気をつけると、思い通りに分岐します。
まとめ
if文は0/非0の評価に基づいてブロックを選ぶ、Cの基本中の基本です。
まずはifの構文と0は偽・非0は真を押さえ、if-elseで二者択一、else ifで多分岐を安全な順序で組み立てましょう。
{ }の徹底、==
/=
の区別、行末;
の確認、早期returnや関数抽出といったベストプラクティスを併用すれば、読みやすく拡張に強い条件分岐が書けます。
最後に、自分の手で小さな問題を解き、挙動と実行結果を都度確認する習慣を身につけてください。