C言語でプログラムを書いていると、必ずと言ってよいほど出てくるのが「条件によって処理を分ける」という考え方です。
その代表的な構文がif文・else文です。
本記事では、C言語初心者の方を対象に、if文とelse文の基本構文から、よくある書き間違い、複数条件の扱い方、そしてバグを防ぐためのポイントまで、実際のサンプルコードを交えながら丁寧に解説していきます。
C言語のif文・else文とは
条件分岐(if文)の基本構文と意味
C言語のif文は、ある条件が真(真偽値として1)である場合にだけ、特定の処理を実行するための構文です。
基本構文は次のようになります。
#include <stdio.h>
int main(void) {
int x = 10;
// if文の基本構文
if (x > 5) {
// 条件が真のときに実行されるブロック
printf("xは5より大きいです。\n");
}
printf("プログラムを終了します。\n");
return 0;
}
xは5より大きいです。
プログラムを終了します。
この例ではx > 5が条件式です。
C言語では、条件式の評価結果が0でない場合を「真」、0の場合を「偽」とみなします。
したがって、xが10のときx > 5は真となり、if文の中のprintfが実行されます。
if文が存在する意味
プログラムは上から順番に命令を実行していくだけでは、単純な動きしかできません。
そこで「条件に応じて別の処理を選ぶ」ためにif文が使われます。
例えば、次のような用途で多用されます。
- 点数が60点以上なら「合格」、それ以外は「不合格」
- 入力された値が0なら特別な扱いをする
- メニュー番号に応じて実行する機能を切り替える
このようにif文は、プログラムに「判断力」を与えるための基本的な構文です。
else文で「それ以外」の処理を書く方法
if文に続けてelse文を使うと、条件が偽だった場合(条件に当てはまらなかった場合)の処理をまとめて書くことができます。
#include <stdio.h>
int main(void) {
int score = 58;
if (score >= 60) {
printf("合格です。\n");
} else {
printf("不合格です。\n");
}
return 0;
}
不合格です。
ifとelseの関係
- ifの条件が真なら、ifブロックだけが実行され、elseブロックは無視されます。
- ifの条件が偽なら、ifブロックは飛ばされ、かわりにelseブロックが実行されます。
ifかelseのどちらか一方だけが実行される、という点が重要です。
条件式で使う比較演算子と論理演算子の基礎
if文の条件式では、値を比較したり、複数の条件を組み合わせたりします。
ここで使うのが比較演算子と論理演算子です。
比較演算子の一覧
次の表は、代表的な比較演算子と意味です。
| 演算子 | 意味 | 例 | 説明 |
|---|---|---|---|
== | 等しい | a == b | aとbが等しければ真 |
!= | 等しくない | a != b | aとbが異なれば真 |
> | より大きい | a > b | aがbより大きければ真 |
< | より小さい | a < b | aがbより小さければ真 |
>= | 以上 | a >= b | aがb以上なら真 |
<= | 以下 | a <= b | aがb以下なら真 |
比較演算子は結果として0または1を返すので、そのままif文の条件として使えます。
論理演算子で条件を組み合わせる
複数の条件を組み合わせたいときは論理演算子を使います。
| 演算子 | 読み方 | 意味 | 例 | ||||
|---|---|---|---|---|---|---|---|
&& | 論理積(AND) | 両方の条件が真なら真 | a > 0 && a < 10 | ||||
| 論理和(OR) | どちらか一方でも真なら真 | a < 0 | a > 100 | |||
! | 否定(NOT) | 条件が真なら偽、偽なら真に反転 | !(a == 0) |
実際の例を見てみます。
#include <stdio.h>
int main(void) {
int score = 75;
// 60以上かつ80未満なら「普通」
if (score >= 60 && score < 80) {
printf("成績は普通です。\n");
}
// 0未満または100より大きいなら「不正な点数」
if (score < 0 || score > 100) {
printf("不正な点数です。\n");
}
return 0;
}
成績は普通です。
このように論理演算子を使うと、現実のルールに近い条件をコードで表現しやすくなります。
if文・else文の書き方とよくある書き間違い
初心者がif文・else文を書くときに、特にミスしやすいポイントがあります。
この章では典型的な書き間違いと、その対策を解説します。
波かっこ(ブロック)の書き忘れと意図しない動作
if文のあとに波かっこ{ }をつけ忘れると、意図と違う処理になります。
C言語では、ifの直後に1文だけなら波かっこなしでも書けてしまうからです。
問題のある例
#include <stdio.h>
int main(void) {
int x = 10;
if (x > 5)
printf("xは5より大きいです。\n");
printf("これは本当に条件付きですか?\n");
return 0;
}
xは5より大きいです。
これは本当に条件付きですか?
2行目のprintfも条件付きだと思ってしまいがちですが、実際にはif (x > 5)にぶら下がっているのは最初の1文だけです。
printf("これは本当に条件付きですか?\n");は、条件に関係なく必ず実行されます。
正しい書き方(波かっこを必ず付ける)
#include <stdio.h>
int main(void) {
int x = 10;
if (x > 5) {
printf("xは5より大きいです。\n");
printf("これは本当に条件付きです。\n");
}
return 0;
}
xは5より大きいです。
これは本当に条件付きです。
1文だけであっても、原則として波かっこを書くようにすると、将来的な修正もしやすく、バグも防げます。
代入(=)と比較(==)の書き間違い
初心者が最もよくやってしまうミスが代入演算子=と比較演算子==の書き間違いです。
間違ったコードの例
#include <stdio.h>
int main(void) {
int flag = 0;
// 「flagが1かどうか」を比較したいつもりが…
if (flag = 1) {
printf("flagは1です。\n");
} else {
printf("flagは1ではありません。\n");
}
return 0;
}
flagは1です。
このコードではflag = 1となっており、比較ではなく代入になっています。
if文の条件部分で代入を行うと、その代入された値が条件式の値になります。
この場合は1が代入されるので、条件式は常に真になってしまいます。
正しい比較の書き方
#include <stdio.h>
int main(void) {
int flag = 0;
if (flag == 1) { // 比較には==を使う
printf("flagは1です。\n");
} else {
printf("flagは1ではありません。\n");
}
return 0;
}
flagは1ではありません。
「等しいかどうか」を判定するときは、必ず==を使うことを意識しておくと、安全にコードが書けます。
セミコロン(;)の付け間違いによるバグ
C言語では行末にセミコロン;を付けるのが基本ですが、if文の直後に誤ってセミコロンを付けてしまうと、非常に分かりにくいバグになります。
典型的なミスの例
#include <stdio.h>
int main(void) {
int x = 10;
if (x > 5); // ← ここに余計なセミコロン
{
printf("xは5より大きいです。\n");
}
return 0;
}
xは5より大きいです。
このコードはぱっと見、条件付きで出力されているように見えますが、実際にはif (x > 5);が1文として終わっており、その後ろのブロックは常に実行される単独のブロックになっています。
セミコロンの位置に注意する
ifの行は次の形になっているかを常に確認するとよいです。
if (条件) {- または
if (条件)のあとに改行して{
ifの行末にセミコロンが付いていないかを目で確認する習慣をつけてください。
条件式に使ってはいけない値・書き方
条件式では0が偽、それ以外が真と評価されるため、思わぬ値をそのまま条件式に書いてしまうとバグの原因になります。
ありがちな危険な書き方
#include <stdio.h>
int main(void) {
int value = 0;
// 「valueが0でないなら」という意味で書いているつもり
if (value) {
printf("valueは0ではありません。\n");
} else {
printf("valueは0です。\n");
}
return 0;
}
valueは0です。
このコードは一応正しく動いていますが、初心者にはif (value)という書き方は意味が分かりづらく、意図が読み取りにくいです。
特に、変数の型や値の範囲が変わったときに誤解を生みやすくなります。
意図が分かる形で書く
次のように明示的な比較を使うと、プログラムの意味がはっきりします。
#include <stdio.h>
int main(void) {
int value = 0;
if (value != 0) {
printf("valueは0ではありません。\n");
} else {
printf("valueは0です。\n");
}
return 0;
}
valueは0です。
「何と比較しているのか」を必ず書くことを心がけると、後から読む自分や他人にとっても理解しやすいコードになります。
複数条件のif-else if-elseの使い方
1つのifと1つのelseだけでは、3パターン以上の分岐を表現しにくくなります。
そのような場合に活躍するのがif-else if-elseの構造です。
if-else if-elseで範囲やランクを判定する
例えば、テストの点数から成績ランクを判定するような場合です。
#include <stdio.h>
int main(void) {
int score = 83;
if (score >= 90) {
printf("成績はAです。\n");
} else if (score >= 80) {
printf("成績はBです。\n");
} else if (score >= 70) {
printf("成績はCです。\n");
} else if (score >= 60) {
printf("成績はDです。\n");
} else {
printf("成績はEです。\n");
}
return 0;
}
成績はBです。
else ifチェーンの特徴
- 上から順番に条件が評価されます。
- 最初に真になったブロックだけが実行され、それ以降の条件は無視されます。
- どの条件にも当てはまらない場合は、最後の
elseが実行されます。
この構造は、「互いに排他的な複数のパターン」を表現するときに非常に便利です。
条件の順番を考えた設計のポイント
上の成績判定の例では、条件の書く順番にも意味があります。
もし順番を間違えると、意図しない結果になります。
悪い順番の例
#include <stdio.h>
int main(void) {
int score = 95;
if (score >= 60) {
printf("60点以上です。\n");
} else if (score >= 90) {
printf("90点以上です。\n");
}
return 0;
}
60点以上です。
このコードでは、scoreが95でも最初のscore >= 60が先に真になるため、score >= 90は評価されません。
一般的なルール
- 範囲が広い条件よりも、範囲が狭い(厳しい)条件を先に書く。
- 「特別扱い」する条件は、先に書いておく。
- 条件が重ならないように(排他的になるように)設計する。
このように考えることで、上から順に読むだけで意味が理解できるif-else if-elseが書けます。
ネスト(ifの入れ子)とelse ifの使い分け
if文の中にさらにif文を書くことをネスト(入れ子)と呼びます。
ネストは便利ですが、深くなりすぎると読みにくくなります。
ネストを使った例
#include <stdio.h>
int main(void) {
int score = 85;
int absent = 0; // 欠席があるかどうか(0ならなし)
if (score >= 80) {
if (absent == 0) {
printf("80点以上かつ欠席なしです。\n");
} else {
printf("80点以上ですが欠席があります。\n");
}
} else {
printf("80点未満です。\n");
}
return 0;
}
80点以上かつ欠席なしです。
条件が「かつ」や「または」で組み合わせられるのであれば、論理演算子を使って1つのifにまとめるほうが読みやすい場合もあります。
else ifで書き換えられる場合
ネスト構造が「同じ項目についての別パターン分岐」であるならば、else ifで書いたほうが見通しがよくなります。
逆に、別の観点の条件で分かれているときは、ネストを使ったほうが自然なこともあります。
初心者のうちは、次のように判断すると良いです。
- 同じ「分類」の条件なら
if / else if / else - 別の観点の条件なら
ifの中にif(ネスト)
複雑な条件を読みやすくする書き方のコツ
条件が増えてくると、if文の行自体が長くなり、意味が分かりにくくなります。
そこで、読みやすさを優先した書き方が重要になります。
条件を変数(フラグ)に分解する
#include <stdio.h>
int main(void) {
int score = 88;
int absent = 0;
int late = 0;
// 条件を一旦フラグとして分けて書く
int isHighScore = (score >= 80);
int hasNoProblem = (absent == 0 && late == 0);
if (isHighScore && hasNoProblem) {
printf("高得点かつ出席状況も良好です。\n");
} else {
printf("条件を満たしていません。\n");
}
return 0;
}
高得点かつ出席状況も良好です。
このように中間の条件に意味のある名前を付けることで、「何を判断しているのか」を自然言語に近い形で表現できます。
括弧を使って意図を明確にする
論理演算子&&と||が混ざるときには、必ず括弧でグループを明示した方が安全です。
// 良くない例(読み手が優先順位を考えないといけない)
if (a > 0 && b > 0 || c > 0) { ... }
// 良い例(意図するグループを括弧で明示)
if ((a > 0 && b > 0) || c > 0) { ... }
if-elseでよくあるバグと注意ポイント
ここでは、実際のプログラムでありがちなif-else関連のバグや注意点をまとめて解説します。
条件の抜け漏れと最後のelseの役割
if-else if-elseを書いているときに、想定していない値が来た場合の扱いを忘れてしまうことがあります。
これが条件の抜け漏れです。
抜け漏れがある例
#include <stdio.h>
int main(void) {
int menu = 5; // 本来は1〜3の想定
if (menu == 1) {
printf("メニュー1を実行します。\n");
} else if (menu == 2) {
printf("メニュー2を実行します。\n");
} else if (menu == 3) {
printf("メニュー3を実行します。\n");
}
return 0;
}
(何も表示されない)
menuに5が入っている場合、どの条件にも当てはまらないため、何も表示されません。
これがバグの温床になります。
最後のelseで異常ケースを拾う
#include <stdio.h>
int main(void) {
int menu = 5;
if (menu == 1) {
printf("メニュー1を実行します。\n");
} else if (menu == 2) {
printf("メニュー2を実行します。\n");
} else if (menu == 3) {
printf("メニュー3を実行します。\n");
} else {
printf("不正なメニュー番号です。(menu = %d)\n", menu);
}
return 0;
}
不正なメニュー番号です。(menu = 5)
最後のelseを「想定外のケースの検出」に使うことで、問題を早く発見できるようになります。
比較対象の型(intやdouble)に注意する
C言語では、整数型(int)と実数型(double)では、比較のときの注意点が異なります。
実数(double)の比較での注意
浮動小数点数は、計算の誤差が入りやすいため、「等しい==」で比較するのは危険です。
#include <stdio.h>
int main(void) {
double x = 0.1 * 3; // 浮動小数点の計算誤差が入る可能性
if (x == 0.3) {
printf("xは0.3です。\n");
} else {
printf("xは0.3ではありません。(x = %f)\n", x);
}
return 0;
}
xは0.3ではありません。(x = 0.300000)
環境によっては0.3と等しくないと判定される場合があります。
浮動小数点の比較では、誤差を許容する書き方が必要です。
#include <stdio.h>
#include <math.h>
int main(void) {
double x = 0.1 * 3;
double eps = 1e-9; // 許容誤差
if (fabs(x - 0.3) < eps) {
printf("xは0.3とほぼ等しいです。\n");
} else {
printf("xは0.3と十分には等しくありません。(x = %.17f)\n", x);
}
return 0;
}
xは0.3とほぼ等しいです。
初心者のうちは、金額や個数など「本当は整数のもの」はintで扱うなど、doubleの使用場面を慎重に選ぶとよいです。
マジックナンバーを避ける条件式の書き方
条件式の中に、意味の分からない「マジックナンバー」が直接書かれていると、後から見たときに意図が分かりにくくなります。
マジックナンバーを使った悪い例
#include <stdio.h>
int main(void) {
int age = 20;
if (age >= 20) {
printf("お酒を購入できます。\n");
}
return 0;
}
この20は、日本では成人年齢や飲酒可能年齢を指しているかもしれません。
しかし、プログラムを別の国で使う場合や、法律が変わる場合には、この「20」を探してすべて書き換えなければならないことになります。
定数を使って意味を明確にする
#include <stdio.h>
#define LEGAL_DRINKING_AGE 20 // 飲酒可能年齢
int main(void) {
int age = 20;
if (age >= LEGAL_DRINKING_AGE) {
printf("お酒を購入できます。\n");
}
return 0;
}
お酒を購入できます。
意味のある名前の定数を使うことで、条件式を読んだときにも意図が一目で分かりますし、値を変更したいときも1か所を書き換えるだけで済みます。
デバッグしやすいif文の書き方と整理方法
if文にバグがあるとき、どこで、どの条件が間違っているのかを特定しにくくなることがあります。
そこで、デバッグしやすい書き方を紹介します。
条件式の値を表示して確認する
#include <stdio.h>
int main(void) {
int score = 65;
printf("デバッグ: score = %d\n", score);
if (score >= 80) {
printf("A判定\n");
} else if (score >= 70) {
printf("B判定\n");
} else if (score >= 60) {
printf("C判定\n");
} else {
printf("D判定\n");
}
return 0;
}
デバッグ: score = 65
C判定
条件に使っている変数の値を一時的に表示することで、思っていた値が本当に入っているかどうかを確認できます。
条件ごとにログメッセージを分ける
複数の条件分岐がある場合、それぞれのブロックに分かりやすいメッセージを入れておくことで、どのルートを通ったかが分かります。
#include <stdio.h>
int main(void) {
int x = -5;
if (x > 0) {
printf("DEBUG: x > 0 の分岐に入りました。\n");
printf("xは正の値です。\n");
} else if (x == 0) {
printf("DEBUG: x == 0 の分岐に入りました。\n");
printf("xは0です。\n");
} else {
printf("DEBUG: x < 0 の分岐に入りました。\n");
printf("xは負の値です。\n");
}
return 0;
}
DEBUG: x < 0 の分岐に入りました。
xは負の値です。
開発中はこのようなデバッグ用出力を活用し、問題が解決したら削除またはコメントアウトする、という運用をするとよいです。
まとめ
本記事では、C言語のif文・else文について、基本構文からよくある書き間違い、複数条件の扱い方、そしてバグを防ぐためのコツまでを解説しました。
特に、波かっこの付け忘れ、=と==の混同、if行末の余計なセミコロンなどは初心者がつまずきやすいポイントです。
条件式は常に「何をどのように判定しているのか」を意識し、意味のある名前や定数を活用することで、読みやすく安全なコードが書けるようになります。
まずは小さなサンプルから、実際にif文・else文を書いて動かしながら、理解を深めていってください。
