この記事は、C言語ドリルの2本目としてif / else(条件分岐)を練習する記事です。値によって動作を変える。「条件によって処理を分ける」書き方を身につけます。

if / elseからswitch文・三項演算子までを7問の練習問題(基礎5問+発展2問)で手を動かして固めるドリルです。解答と解説は各問題の「+」を押すと開きます。まず自分で書いてみて、それから答え合わせをしてください。ここでは前回の変数・型・演算子で学んだ比較演算子(== など)が主役になります。

<自己紹介>
筆者は現役の組込みエンジニアです。未経験向けのC言語練習問題を通じて最低限の言語知識を身につけ、最終的にはArduinoでマイコンプログラムを自作できるようになるのをゴールとして、このシリーズを作成しています。

このテーマの要点

条件分岐でやることはこれだけ

  • if (条件) で「条件が真のときだけ」処理する。else / else if で「そうでないとき」を分ける
  • 値ごとの分岐が多いなら switch、1行で書ける簡単な分岐なら三項演算子
  • 条件は比較(== >= など)と論理(&& ||)で組み立てる

ここまでのプログラムは、上から下へ順番に実行されるだけでした。条件分岐を覚えると、入力や状態に応じて振る舞いを変えるプログラムが書けるようになります。組込みソフトではセンサーの値で機器の動作を切り替えるようなプログラムを書いたりします。

前提知識:if・else・switch・三項演算子

C言語の条件分岐は、次の5種類に整理できます。まず全体を眺めてから、1つずつ見ていきましょう。

書き方 いつ使う
if 条件が成立(真)した場合だけ実行する
if...else 成立ならifの中、不成立ならelseの中を実行する
if...else if 複数の条件を上から順に評価し、最初に成立した1つを実行する
switch 1つの値が「どのcaseと一致するか」で分岐する
三項演算子 ?: 簡単な二択の分岐を1行で書く

① if・if / else・else if

3つの基本形

if (score >= 60) {
    printf("合格\n");     // 条件が真のときだけ実行
}

if (score >= 60) {
    printf("合格\n");
} else {
    printf("不合格\n");   // 条件が偽のとき
}

if (temp >= 28) {
    printf("暑い\n");
} else if (temp >= 20) {
    printf("快適\n");     // 上が偽で、これが真のとき
} else {
    printf("寒い\n");     // どれも偽のとき
}
メモ:else if は上から順に判定される
else if上から順にチェックし、最初に真になったところだけ実行します。だから「範囲の狭い条件・厳しい条件から先に書く」のが基本です。順番を間違えると、意図しない分岐に入ります。
if、else if、elseが上から順に判定されるフロー図
図:if → else if → else の判定の流れ。実行されるのは最初に成立した1つだけ

② 条件を作る道具(比較演算子と論理演算子)

条件のところに書けるのは、真(成立)か偽(不成立)かが決まる式です。前回の復習を兼ねて、一覧にしておきます。

演算子 意味 真になる例
== / != 等しい / 等しくない x == 5(xが5のとき)
> / < より大きい / より小さい x > 0(xが1以上のとき)
>= / <= 以上 / 以下(境界を含む) x >= 60(xが60ちょうどでも真)
&& かつ(両方が真) x >= 25 && x <= 30
|| または(どちらかが真) x < 0 || x > 100
! 否定(真偽を反転) !(x == 5)(xが5でないとき)

論理演算子は最初は少しイメージしづらいかもしれませんが、練習問題を解いていくうちに感覚的に分かるようになります。まずは手を動かして覚えていくのが近道です。

③ switch文(値ごとの分岐が多いとき)

「モードが0なら停止、1なら前進、2なら後退」のように、1つの値がどれに一致するかで分けるなら、switch文の方がすっきり書けます。

switchの形

switch (mode) {      // ここに判定したい値を書く
case 0:
    printf("停止\n");
    break;           // caseの最後には必ずbreak
case 1:
    printf("前進\n");
    break;
default:             // どのcaseとも一致しないとき(省略可)
    printf("不明\n");
    break;
}

caseはいくつでも書けます。1つ注意があり、caseの最後の break を忘れると、次のcaseまで続けて実行されてしまいます(フォールスルーといいます)。「caseを書いたらセットでbreak」と覚えてください。

④ 三項演算子(簡単な二択を1行で)

三項演算子の形

// 条件 ? 真のときの値 : 偽のときの値
int max = (a > b) ? a : b;   // aとbの大きい方をmaxに入れる

if / elseで4行かかる二択を1行にできます。ただし複雑な条件を詰め込むと読みにくくなるので、「どちらかの値を選ぶ」程度の簡単な場面だけで使うのがおすすめです。
※あまり使う頻度は高くないですし、正直覚えなくてもいいかなという内容なので無理して理解はしなくていいです。あくまでこういう書き方もあるよということで。

より正確な仕様は、cppreference(C言語リファレンス)で確認できます。

例題(まずは一緒に解いてみる)

練習問題に入る前に、簡単な例題を1つ、答えを見ながら流れを確認しましょう。

例題:点数 score = 8070以上なら「pass」、そうでなければ「study」と表示してみましょう。

example.c

#include <stdio.h>

int main(void) {
    int score = 80;
    if (score >= 70) {
        printf("pass\n");
    } else {
        printf("study\n");
    }
    return 0;
}

実行結果:pass

解説:score は80で、score >= 70(70以上)が真なので if の中が実行され「pass」。もし60なら条件が偽になり、else の「study」が表示されます。条件が真なら if、偽なら else、という流れです。

流れはつかめましたか? ここからは、自分の手で解いてみましょう。

練習問題(基礎5+発展2)

基礎5問は必ず解いてください。発展2問は余力があればで大丈夫です。まず自分で書いてから、各問題の「+ 解答・解説を見る」を開いて答え合わせをしましょう。

基礎 Q1

整数の変数 x に 7 を入れ、x正の数(0より大きい)のときだけ positive と表示するプログラムを書いてください。

解答・解説を見る
q1.c

#include <stdio.h>

int main(void) {
    int x = 7;
    if (x > 0) {
        printf("positive\n");
    }
    return 0;
}

実行結果:positive

解説:if (条件){ } の中は、条件が真のときだけ実行されます。x > 0 は「xは0より大きいか?」の比較で、7は0より大きいので真。もし x-3 なら偽になり、何も表示されません。

基礎 Q2

テストの点数 score(72点)が 60点以上なら pass、そうでなければ fail と表示してください。else を使います。

解答・解説を見る
q2.c

#include <stdio.h>

int main(void) {
    int score = 72;
    if (score >= 60) {
        printf("pass\n");
    } else {
        printf("fail\n");
    }
    return 0;
}

実行結果:pass

解説:else は「if の条件が偽だったとき」に実行されます。これで必ずどちらか一方が実行されます。>= は「以上」(60を含む)。「より大きい」の > とは違うので、境界の60点をどう扱うかで使い分けます。

基礎 Q3

気温 temp(28)を、28以上なら「hot」、20以上なら「comfortable」、それ未満なら「cold」の3つに分けて表示してください。else if を使います。

解答・解説を見る
q3.c

#include <stdio.h>

int main(void) {
    int temp = 28;
    if (temp >= 28) {
        printf("hot\n");
    } else if (temp >= 20) {
        printf("comfortable\n");
    } else {
        printf("cold\n");
    }
    return 0;
}

実行結果:hot

解説:else if は上から順に判定し、最初に真になった1つだけを実行します。28は最初の temp >= 28 で真になるので、そこで確定して残りは見ません。もし条件を「20以上」から先に書くと、28でも「comfortable」になってしまいます。厳しい条件から先に書くのがコツです。

基礎 Q4

夜(isNight が 1)」かつ「暗い(light が 300未満)」のときだけ LED ON、それ以外は LED OFF と表示してください。&&(かつ)を使います。isNight = 1light = 200 とします。

解答・解説を見る
q4.c

#include <stdio.h>

int main(void) {
    int isNight = 1;
    int light = 200;
    if (isNight == 1 && light < 300) {
        printf("LED ON\n");
    } else {
        printf("LED OFF\n");
    }
    return 0;
}

実行結果:LED ON

解説:&& は「両方が真なら真」。夜(isNight == 1)で、かつ暗い(light < 300)ので、両方真=点灯です。ここで isNight = 1(イコール1つ)と書くと代入になってバグります。比較は必ず == を思い出してください。

基礎 Q5

動作モード mode(0=停止、1=前進、2=後退)の値に応じて、stopforwardback のどれかを表示してください。switch文を使い、0・1・2のどれでもない値なら error と表示します。mode = 2 とします。

解答・解説を見る
q5.c

#include <stdio.h>

int main(void) {
    int mode = 2;
    switch (mode) {
    case 0:
        printf("stop\n");
        break;
    case 1:
        printf("forward\n");
        break;
    case 2:
        printf("back\n");
        break;
    default:
        printf("error\n");
        break;
    }
    return 0;
}

実行結果:back

解説:switch は「1つの値がどのcaseに一致するか」で分岐します。mode が2なので case 2 の処理が実行されます。各caseの最後の break を忘れると、下のcaseまで続けて実行されてしまうので注意してください(試しにQ5のbreakを消して動かすと、backとerrorが両方表示されます)。default は「どれにも当てはまらないとき」の受け皿で、想定外の値を検出するのに役立ちます。

発展 Q6

2つの整数 a = 40b = 65大きい方を、三項演算子を使って1行で変数 max に入れて表示してください。

解答・解説を見る
q6.c

#include <stdio.h>

int main(void) {
    int a = 40, b = 65;
    int max = (a > b) ? a : b;   // 真ならa、偽ならb
    printf("max=%d\n", max);
    return 0;
}

実行結果:max=65

解説:三項演算子は「条件 ? 真のときの値 : 偽のときの値」の形で、式として値を返すのが特徴です。だから if / else と違い、そのまま代入の右辺に書けます。「大きい方を選ぶ」「範囲内に収める」のような値選びに向いています。逆に、処理を何行も書きたい場合は素直に if / else を使ってください。

発展 Q7

明るさ light と、今のLEDの状態 ledState(0=消灯 / 1=点灯)がある。300未満なら点灯、700より明るければ消灯、その間(300〜700)は今の状態のままにして、最後の ledState を表示してください。light = 500ledState = 0 から始めます。

解答・解説を見る
q7.c

#include <stdio.h>

int main(void) {
    int light = 500;
    int ledState = 0;
    if (light < 300) {
        ledState = 1;        // 暗い→点灯
    } else if (light > 700) {
        ledState = 0;        // 明るい→消灯
    }
    // 300〜700は現状維持(ledStateを変えない)
    printf("ledState=%d\n", ledState);
    return 0;
}

実行結果:ledState=0

解説:ポイントは「どの条件にも当てはまらないときは、何もしない=今の状態を保つ」ことです。else を付けずに中間帯を放置するのがコツ。試しに light を 200 にすれば 1(点灯)、800 にすれば 0(消灯)になり、今回の 500 のように中間のときだけ元の状態が保たれます。しきい値ピッタリ付近でセンサー値が揺れても状態が固定されるので、出力がバタつきません。この考え方(ヒステリシス)は、実際のセンサー制御でよく使います。

この発展問題は余力がある人向けです。基礎5問ができていれば、次のテーマ(ループ)に進んで大丈夫です。

例:実務で実際に書くコード

条件分岐は、組込みの「入力を見て動作を決める」場面の主役です。マイコンのプログラムでは、こんな形で毎日登場します。

例:明るさセンサーで照明を制御する

int light = read_sensor();   // 明るさを読む(0〜1023)

if (light < 300) {           // 暗い?
    led_on();                // 点灯
} else {
    led_off();               // 消灯
}
  • センサーやスイッチの入力値を、そのまま if の条件にして動作を分けます
  • 「暑い/快適/寒い」のように段階で動きを変えるなら else if、動作モードごとの分岐なら switch
  • 「夜 かつ 暗い」のように複数条件を重ねるなら &&||

私が車載の現場で書く制御コードも、中心はこの形です。特にswitch文は「今どの状態(モード)か」で処理を切り替える状態遷移の実装で多用します。そして、しきい値でのオン・オフ判定には、発展Q7で試したヒステリシス(反応する値と戻す値をずらす)を持たせて、センサー値が揺れても誤動作しないようにするのが定番です。

最後につまずきポイントをおさらい

条件で「=」を1つ書くと、いつも真になる
if (isNight = 1) のように = を1つで書くと、比較ではなく代入になり、条件が常に真になってしまいます。分岐が意図どおりに動かないときは、まず == の書き忘れを疑ってください(前回のつまずきと同じ場所です)。

あと2つ、定番のつまずきを挙げておきます。1つ目は else if の順番です。範囲がゆるい条件を先に書くと、厳しい条件までたどり着けません。「28以上」を「20以上」より先に書く、というように狭い条件から順に並べましょう。2つ目は switchの break 忘れです。忘れても文法エラーにはならず、下のcaseまで実行されて「なぜか2つ動く」バグになります。

よくある質問(FAQ)

{ } は省略できる?

1行だけなら省略できますが、付ける習慣にするのがおすすめです。省略すると、後から行を足したときに「if の中のつもりが外だった」というバグが起きやすくなります。

else if と switch はどう使い分ける?

「範囲」で分けるなら else if(60点以上、20度以上など)、「値の一致」で分けるなら switch(モード0/1/2など)が読みやすいです。迷ったら、まず else if で書いてみて、caseの羅列になってきたらswitchに直せば十分です。

「かつ」と「または」を混ぜるときは?

( ) で囲んでまとまりを作ると安全です。(A && B) || C のように書くと、意図した優先順位で判定できます。

次に読む

条件で動作を分けられるようになったら、次は「繰り返し」で同じ処理を何度も回す練習です。

次のドリル(#3)C言語 ループの練習問題7問|for・while・do-whileを固める
前のドリル(#1)C言語 変数・型・演算子の練習問題7問|=と==の違いも図解
目次へ戻るC言語 基礎ドリル|組込みに必要な8テーマの練習問題まとめ