ループ構造

ループは陸上トラックの周回走のようなものです——ゴールラインに達するまで走り続けます。条件が満たされたら止まる。ループがあれば、プログラムは一度きりの実行にとどまらず、繰り返し処理ができるようになります。

whileループ

whileは最も基本的なループです。まず条件を確認し、真ならループ本体を実行し、再び条件を確認する、という繰り返しで条件が偽になるまで続けます。

C
#include <stdio.h>

int main(void) {
    int count = 1;
    while (count <= 5) {
        printf("Lap %d\n", count);
        count++;
    }
    printf("Done!\n");
    return 0;
}
TEXT
Lap 1
Lap 2
Lap 3
Lap 4
Lap 5
Done!
⚠️ 注意: ループ本体には、最終的に条件を偽にする操作(count++など)が必ず必要です。さもないと無限ループになり、プログラムが永遠に止まらなくなります。

whileを使う場面

繰り返し回数が不定で実行時の条件に依存する場合、whileが最も自然な選択です。例えば、特定の値が入力されるまで読み込みを続ける場合などです。

C
#include <stdio.h>

int main(void) {
    int sum = 0;
    int num = 0;
    printf("Enter positive integers to sum, 0 to finish: ");
    scanf("%d", &num);
    while (num != 0) {
        sum += num;
        scanf("%d", &num);
    }
    printf("Sum: %d\n", sum);
    return 0;
}
TEXT
Enter positive integers to sum, 0 to finish: 10 20 30 0
Sum: 60

do-whileループ

do-whileはまずループ本体を実行してから条件を確認します。ループ本体が必ず少なくとも1回は実行されることが、whileとの決定的な違いです。

C
#include <stdio.h>

int main(void) {
    int num;
    do {
        printf("Enter a number 1-10: ");
        scanf("%d", &num);
    } while (num < 1 || num > 10);
    printf("You entered: %d\n", num);
    return 0;
}
TEXT
Enter a number 1-10: 15
Enter a number 1-10: 0
Enter a number 1-10: 7
You entered: 7
⚠️ 注意: do-whileの末尾のセミコロンは省略できません。} while (condition); セミコロンを忘れるとコンパイルエラーになります。

whileとdo-whileの使い分け

forループ

forは初期化、条件確認、更新をヘッダーにまとめる、最もよく使われるループ形式です。

C
for (initialization; condition; update) {
    loop body;
}
C
#include <stdio.h>

int main(void) {
    for (int i = 1; i <= 5; i++) {
        printf("%d ", i);
    }
    printf("\n");
    return 0;
}
TEXT
1 2 3 4 5

forループの実行フロー

  1. 初期化を実行(1回だけ)
  2. 条件を確認——偽ならループを抜ける
  3. ループ本体を実行
  4. 更新を実行
  5. 手順2に戻る

forの柔軟性

forの3つの部分はすべて省略可能ですが、セミコロンは残す必要があります。

C
#include <stdio.h>

int main(void) {
    int i = 1;
    for (; i <= 5; ) {
        printf("%d ", i);
        i++;
    }
    printf("\n");
    return 0;
}

条件を省略すると無限ループになります。for (;;) {}while (1) {}と等価です。

💡 ヒント: forループを優先しましょう。ループ変数、境界条件、更新方法が一目でわかるため、うっかり無限ループを書く危険が少なくなります。

スコープの考慮

C99ではforの初期化部で変数を宣言できます。その変数はforループ内でのみ有効です。

C
#include <stdio.h>

int main(void) {
    for (int i = 0; i < 3; i++) {
        printf("i = %d\n", i);
    }
    return 0;
}

ループ終了後、iにはアクセスできません。ループ外でiを使う必要がある場合は、forの前に宣言してください。

ネストされたループ

ループの中に別のループを入れたものがネストされたループです。外側のループの各反復で、内側のループが1回完全に実行されます。

星形の長方形を出力

C
#include <stdio.h>

int main(void) {
    int rows = 3;
    int cols = 5;
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("* ");
        }
        printf("\n");
    }
    return 0;
}
TEXT
* * * * *
* * * * *
* * * * *

九九の表

C
#include <stdio.h>

int main(void) {
    for (int i = 1; i <= 9; i++) {
        for (int j = 1; j <= i; j++) {
            printf("%d*%d=%-4d", j, i, i * j);
        }
        printf("\n");
    }
    return 0;
}
TEXT
1*1=1
1*2=2   2*2=4
1*3=3   2*3=6   3*3=9
1*4=4   2*4=8   3*4=12  4*4=16
1*5=5   2*5=10  3*5=15  4*5=20  5*5=25
1*6=6   2*6=12  3*6=18  4*6=24  5*6=30  6*6=36
1*7=7   2*7=14  3*7=21  4*7=28  5*7=35  6*7=42  7*7=49
1*8=8   2*8=16  3*8=24  4*8=32  5*8=40  6*8=48  7*8=56  8*8=64
1*9=9   2*9=18  3*9=27  4*9=36  5*9=45  6*9=54  7*9=63  8*9=72  9*9=81
⚠️ 注意: ネストされたループの総反復回数は外側と内側の回数の積になります。3レベルのネストは指数的な増大を招くため、パフォーマンスに注意してください。

break文

breakは現在のループをただちに抜けます(1レベルだけ)。残りの反復はスキップされます。

C
#include <stdio.h>

int main(void) {
    for (int i = 1; i <= 10; i++) {
        if (i == 5) {
            break;
        }
        printf("%d ", i);
    }
    printf("\nStopped at 5\n");
    return 0;
}
TEXT
1 2 3 4
Stopped at 5

条件を満たす最初の要素を見つける

C
#include <stdio.h>

int main(void) {
    int nums[] = {3, 7, 2, 9, 5, 1};
    int target = 9;
    int found = 0;
    for (int i = 0; i < 6; i++) {
        if (nums[i] == target) {
            printf("Found %d at index %d\n", target, i);
            found = 1;
            break;
        }
    }
    if (!found) {
        printf("%d not found\n", target);
    }
    return 0;
}
TEXT
Found 9 at index 3

continue文

continueは現在の反復の残りの文をスキップし、次の反復にジャンプします(条件確認または更新手順に戻ります)。

C
#include <stdio.h>

int main(void) {
    for (int i = 1; i <= 10; i++) {
        if (i % 3 == 0) {
            continue;
        }
        printf("%d ", i);
    }
    printf("\nMultiples of 3 skipped\n");
    return 0;
}
TEXT
1 2 4 5 7 8 10
Multiples of 3 skipped
⚠️ 注意: whiledo-whileループでcontinueを使う場合、更新文がcontinueよりも前にあることを確認してください。さもないと無限ループになる可能性があります。

よくあるループパターン

カウントパターン

条件を満たす要素の数を数えます。

C
#include <stdio.h>

int main(void) {
    int nums[] = {12, 45, 3, 67, 89, 23, 56};
    int count = 0;
    for (int i = 0; i < 7; i++) {
        if (nums[i] > 50) {
            count++;
        }
    }
    printf("Numbers greater than 50: %d\n", count);
    return 0;
}
TEXT
Numbers greater than 50: 3

累積パターン

一連の値を合計します。

C
#include <stdio.h>

int main(void) {
    int sum = 0;
    for (int i = 1; i <= 100; i++) {
        sum += i;
    }
    printf("Sum from 1 to 100: %d\n", sum);
    return 0;
}
TEXT
Sum from 1 to 100: 5050

探索パターン

条件を満たす最初の要素を見つけ、breakで抜けます。前出のbreakの例を参照してください。

走査パターン

配列の各要素を順番に処理します。

C
#include <stdio.h>

int main(void) {
    int scores[] = {85, 92, 78, 96, 61};
    int len = 5;
    for (int i = 0; i < len; i++) {
        printf("Student%d: %d %s\n", i + 1, scores[i], scores[i] >= 60 ? "Pass" : "Fail");
    }
    return 0;
}
TEXT
Student1: 85 Pass
Student2: 92 Pass
Student3: 78 Pass
Student4: 96 Pass
Student5: 61 Pass

無限ループとその回避方法

無限ループとは、条件が常に真であるループです。意図的な無限ループはfor(;;)while(1)を使い、内部でbreakで抜けます。

C
#include <stdio.h>

int main(void) {
    int num;
    while (1) {
        printf("Enter a number (0 to quit): ");
        scanf("%d", &num);
        if (num == 0) {
            break;
        }
        printf("You entered: %d\n", num);
    }
    printf("Goodbye!\n");
    return 0;
}

意図しない無限ループは、ループ変数が更新されない、または間違った方向に更新されることが原因で発生します。

C
int i = 0;
while (i < 10) {
    printf("%d", i);
}
⚠️ 注意: プログラムが「フリーズ」したように見える場合、まず疑うべきは無限ループです。Ctrl+Cで強制終了してください。

ネストされたループで直角三角形を出力します。

C
#include <stdio.h>

int main(void) {
    int n = 5;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= i; j++) {
            printf("* ");
        }
        printf("\n");
    }
    return 0;
}
▶ 試してみよう
TEXT
*
* *
* * *
* * * *
* * * * *

ユークリッドの互除法で2つの正の整数の最大公約数を求めます。反復回数が不定なwhileループの実例です。

C
#include <stdio.h>

int main(void) {
    int a = 48, b = 18;
    int orig_a = a, orig_b = b;
    while (b != 0) {
        int temp = a % b;
        a = b;
        b = temp;
    }
    printf("GCD of %d and %d is %d\n", orig_a, orig_b, a);
    return 0;
}
▶ 試してみよう
TEXT
GCD of 48 and 18 is 6

3種のループの使い分け

状況 推奨
反復回数が固定 for
少なくとも1回は実行が必要 do-while
反復回数が不定 while
対話型メニュー do-while + switch
💡 ヒント: 3種のループは論理的に相互変換可能です。用途に最も合ったものを選んでください。

❓ よくある質問

Q forwhileはどちらを使うべきですか?
A 反復回数が分かっている場合はfor、そうでない場合はwhileを使うのが最も広く受け入れられているガイドラインです。
Q breakで複数レベルのループを抜けられますか?
A いいえ。breakは最内側のループしか抜けません。複数レベルを抜けるには、フラグ変数と外側ループの確認を組み合わせるか、gotoを使います(推奨されませんが実用的な場合があります)。
Q for(;;)while(1)はどちらが良いですか?
A 機能的には等価です。while(1)のほうが読みやすく、for(;;)は伝統的なCスタイルです。チームの規約に従ってください。
Q ループ変数にijkを使ってもよいですか?
A 単純なループでは広く受け入れられた慣習です。ただし、変数に業務的な意味がある場合(例:rowcolstudent_index)は、説明的な名前が良いです。

📖 まとめ

📝 練習問題

  1. forループを使って階乗の和 1! + 2! + 3! + ... + 10! を計算するプログラムを書いてください。
  2. ネストされたループを使って、逆直角三角形(5行で、1行目に星5個、5行目に星1個)を出力するプログラムを書いてください。
  3. 正の整数を読み込み、その桁を逆順に出力するプログラムを書いてください(例:1234の入力で4 3 2 1と出力)。
100%