【第2回】ゼロから始めるC言語 制御構文

C言語

はじめに

今回はC言語における制御構文について学んでいく。
この記事には各制御構文に関するいくつかの例題を用意しているので、理解を深めるために取り組んでみてほしい。

1. 条件分岐(if)

if (条件1) {
    // 条件1が真の場合に実行されるステートメント
} else if (条件2) {
    // 条件1が偽で条件2が真の場合に実行されるステートメント
} else {
    // すべての条件が偽の場合に実行されるステートメント
}

条件分岐の書き方は非常にシンプル。
次の具体的なプログラムを実行し、条件分岐の動作を確認してみよう。

grade.c
#include <stdio.h>

int main() {
    int score;
    printf("点数を入力してください (0-100): ");
    scanf("%d", &score);

    if (score >= 90) {
        printf("Grade: A\n");
    } else if (score >= 80) {
        printf("Grade: B\n");
    } else if (score >= 70) {
        printf("Grade: C\n");
    } else if (score >= 60) {
        printf("Grade: D\n");
    } else {
        printf("Grade: F\n"); 
    }

    return 0;
}

このコードは、ユーザーに点数を入力させ、入力された点数に応じて以下のように表示させるプログラムである。

  • 入力された点数が90点以上の場合は、「Grade: A」と表示
  • 点数が80点以上90点未満の場合は、「Grade: B」と表示
  • 点数が70点以上80点未満の場合は、「Grade: C」と表示
  • 点数が60点以上70点未満の場合は、「Grade: D」と表示
  • 60点未満では、「Grade: F」と表示

しかし、このプログラムには問題がある。
ユーザーから(0-100)の範囲外を入力された場合の処理について実装していない。

例題1
上記のプログラムで、ユーザーが入力した点数が範囲内(0-100)であるかどうかをチェックするための機構を考えて、コードを修正してみよう。

解答例

if文をさらに使うことで、ユーザーの入力を受け取る変数scoreが0-100の範囲内に収まるかどうかを確認する機構を実装した。if文の中にif文があるような入れ子構造をネストと呼ぶ。
最初のif文で用いた論理演算子||については、次の項で解説する。

grade.c
#include <stdio.h>

int main() {
    int score;
    printf("点数を入力してください (0-100): ");
    scanf("%d", &score);

    // 点数が0から100の範囲内かどうかをチェック
    if (score < 0 || score > 100) {
        printf("0-100の範囲で入力してください\n");
    } else {
        // 範囲内の場合、成績を評価
        if (score >= 90) {
            printf("Grade: A\n");
        } else if (score >= 80) {
            printf("Grade: B\n");
        } else if (score >= 70) {
            printf("Grade: C\n");
        } else if (score >= 60) {
            printf("Grade: D\n");
        } else {
            printf("Grade: F\n"); 
        }
    }

    return 0;
}

論理演算子

演算子説明使用例
&&論理AND。両方のオペランドが真である場合に真を返すexpr1 && expr2: expr1とexpr2が両方とも真の場合に真
||論理OR。いずれかのオペランドが真であれば真を返すexpr1 || expr2: expr1またはexpr2の少なくとも一方が真の場合に真
!論理NOT。オペランドが偽であれば真を返し、真であれば偽を返す!expr: exprが偽の場合に真

先ほどの解答例で用いた||は、scoreが0未満もしくは100より大きい場合に実行されることがわかる。

if (score < 0 || score > 100)

2. 条件分岐(switch)

switch (式) {
    case 値1:
        // 式が値1に等しい場合に実行されるステートメント
        break;
    case 値2:
        // 式が値2に等しい場合に実行されるステートメント
        break;
    default:
        // どのcaseもマッチしなかった場合に実行されるステートメント
}

switch文を用いると、1つの変数の値に基づいて多数のブロックの中から1つを実行することができる。
こちらも具体的なプログラムで動作を見ていこう。

number.c
#include <stdio.h>

int main() {
    int dayNumber;
    printf("番号を入力してください (1-7): ");
    scanf("%d", &dayNumber);

    switch (dayNumber) {
        case 1:
            printf("Sunday\n");
            break;
        case 2:
            printf("Monday\n");
            break;
        case 3:
            printf("Tuesday\n");
            break;
        case 4:
            printf("Wednesday\n");
            break;
        case 5:
            printf("Thursday\n");
            break;
        case 6:
            printf("Friday\n");
            break;
        case 7:
            printf("Saturday\n");
            break;
        default:
            printf("1-7の範囲で入力してください\n");
            break;
    }
    return 0;
}

このコードは、ユーザーから1-7の入力を受け取り、入力された番号に基づいて曜日を表示させるプログラムである。

  • case ラベルは1から7までの数字に対応し、それぞれの曜日を表示する
  • default ケースは、1から7の範囲外の入力があった場合に実行され、エラーメッセージを表示する

switch文は特定の値に基づいて異なる処理を行いたい場合に適しており、複数のif-else文を使うよりもコードが読みやすくなる。

breakとcontinue

先ほどのswitch文を使った例で、breakというステートメントが登場したので、その効果を確認しておこう。後述の繰り返し処理で登場するが、continueもセットで理解しておくと良い。

break

ループや switch 文から制御を抜け出すために使用される。ループ内で break が実行されると、ループはその時点で終了し、ループの外の次の文へ制御が移る。

continue

ループの次の繰り返しに進み、現在の繰り返しはそこで終了する。continue が実行されると、ループ内のその後のコードはスキップされ、ループの次の反復の開始条件評価へと直接移る。

まとめ

  • break: ループや switch 文から完全に抜け出し、ループの次の部分に制御を移す
  • continue: ループの現在の反復を終了し、次の反復へ制御を移す。ただしループは終了せず、次の反復条件の評価が続行される

3. 繰り返し(for)

for (初期化式; 条件式; 更新式) {
    // 繰り返す処理
}

for文は繰り返し処理を実装する際に使われる。
こちらも具体的なプログラムで考えていく。先ほど登場したcontinueも使われているので注意しながら見てみよう。

loop.c
#include <stdio.h>

int main() {
    for (int i = 1; i <= 10; i++) {
        if (i % 2 == 0) {
            continue; 
        }
        printf("%d ", i);
    }
    return 0;
}

例題2
上のコードの実行結果を予想してみよう。コンソールには何が出力されるだろうか?

解答例

出力結果は次のとおり。予想は合っていただろうか?

1 3 5 7 9

今回のfor文ではint型の変数iに1を代入して初期化し、繰り返す中でiが10以下であれば処理を行い、iを1ずつ増やしていくという繰り返し処理を実装している。今回はループの回数に応じて1から10までの整数が順番にiに代入されることになる。

for (int i = 1; i <= 10; i++)

これをif文によって偶数と奇数に分け、iが偶数である場合にはcontinueするので、iが偶数の場合はプリントが行われない。よって奇数だけが出力されることになる。

インクリメントとデクリメント

インクリメント演算子 ++ は、変数の値を1だけ増加させる。i++は、i = i + 1と同じ意味。
この演算子には、前置と後置の二つの形式がある。

  • 前置インクリメント (++i): 変数の値を増やしてから、その式の評価を行う
  • 後置インクリメント (i++): 変数の値を評価してから、その値を増やす

同様に、デクリメント演算子–は変数の値を1だけ減少させる。

  • 前置デクリメント (--i): 変数の値を減少させてから、その式の評価を行う
  • 後置デクリメント (i--): 変数の値を評価してから、その値を減少させる

4. 繰り返し(while / do-while)

while (条件) {
    // 繰り返す処理
}

do {
    // 繰り返す処理
} while (条件);

while文は条件が真の間、ループを続ける。do-while文では、一度ループ本体を実行し、その後条件が真の間ループを続ける。最低1回はループ本体が実行されることになる。

例題3
先ほど「3. 繰り返し(for)」内で扱った「1-10の中で奇数だけ出力するプログラム」を、while文を使って書き換えてみよう

解答例

loop_2.c
#include <stdio.h>

int main() {
    int i = 1; 
    while (i <= 10) {
        if (i % 2 == 0) {
            i++;
            continue; 
        }
        printf("%d ", i);
        i++; 
    }
    return 0;
}

更新式をループの中に書くのがポイント。

タイトルとURLをコピーしました