第6章:繰り返しの力
この章で学ぶこと
- ループ(繰り返し)の概念
- while文
- for文
- do-while文
- ループ制御(break, continue)
- 無限ループ
- ネストしたループ
---
6.1 ループとは
同じ処理を繰り返す
「1から10までの数を表示する」プログラムを考えてみましょう。
ループを使わない場合:
printf("1\n");
printf("2\n");
printf("3\n");
printf("4\n");
printf("5\n");
printf("6\n");
printf("7\n");
printf("8\n");
printf("9\n");
printf("10\n");
10行も書く必要があります。100まで表示するなら100行、1000なら...想像するだけで大変です。
ループを使う場合:
for (int i = 1; i <= 10; i++) {
printf("%d\n", i);
}
たった3行で済みます。1000回でも同じです。
ループの種類
C言語には3種類のループがあります:
---
6.2 while文
基本形
while (条件) {
// 条件が真の間、繰り返し実行される
}
条件が真(true)の間、波括弧内の処理が繰り返し実行されます。
使用例
#include <stdio.h>
int main(void)
{
int count = 1;
while (count <= 5) {
printf("Count: %d\n", count);
count++; // カウンターを増やす
}
printf("Done!\n");
return 0;
}
出力:
Count: 1
Count: 2
Count: 3
Count: 4
Count: 5
Done!
実行の流れ
count = 1count <= 5→ 1 <= 5 → 真 → ループ内を実行- "Count: 1" を表示
count++→count = 2count <= 5→ 2 <= 5 → 真 → ループ内を実行- ... (繰り返し)
count = 6のとき、count <= 5→ 偽 → ループ終了- "Done!" を表示
- 初期化: ループに入る前にカウンター変数を初期化
- 条件: いつか必ず偽になる条件を設定
- 更新: ループ内でカウンターを変更
while文のポイント
これらを忘れると無限ループになります。
---
6.3 for文
基本形
for (初期化; 条件; 更新) {
// 条件が真の間、繰り返し実行される
}
使用例
#include <stdio.h>
int main(void)
{
for (int i = 1; i <= 5; i++) {
printf("Count: %d\n", i);
}
printf("Done!\n");
return 0;
}
出力(whileの例と同じ):
Count: 1
Count: 2
Count: 3
Count: 4
Count: 5
Done!
forとwhileの比較
// for文
for (int i = 0; i < 10; i++) {
printf("%d\n", i);
}
// 同等のwhile文
int i = 0;
while (i < 10) {
printf("%d\n", i);
i++;
}
forは「初期化・条件・更新」が1行にまとまっているため、繰り返し回数が決まっている場合に適しています。
様々なforの使い方
// 0から9まで(10回)
for (int i = 0; i < 10; i++) { }
// 1から10まで(10回)
for (int i = 1; i <= 10; i++) { }
// 10から1までカウントダウン
for (int i = 10; i >= 1; i--) { }
// 2ずつ増加
for (int i = 0; i < 10; i += 2) { }
// 複数の変数
for (int i = 0, j = 10; i < j; i++, j--) { }
カウンター変数の名前
ループのカウンター変数には、慣習的に i, j, k がよく使われます。
for (int i = 0; i < 10; i++) { } // 1つ目のループ
for (int j = 0; j < 10; j++) { } // ネストした2つ目
for (int k = 0; k < 10; k++) { } // ネストした3つ目
ただし、意味のある名前を使う方が良い場合もあります:
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
// ...
}
}
---
6.4 do-while文
基本形
do {
// 最低1回は実行される
} while (条件); // セミコロンに注意!
do-while は条件チェックが後に行われます。そのため、ループ内の処理が最低1回は実行されることが保証されます。
使用例
#include <stdio.h>
int main(void)
{
int count = 1;
do {
printf("Count: %d\n", count);
count++;
} while (count <= 5);
printf("Done!\n");
return 0;
}
whileとdo-whileの違い
int x = 10;
// while: 条件が最初から偽なら、1回も実行されない
while (x < 5) {
printf("while: %d\n", x);
x++;
}
// 何も表示されない
// do-while: 最低1回は実行される
do {
printf("do-while: %d\n", x);
x++;
} while (x < 5);
// "do-while: 10" が表示される
do-whileの典型的な使用場面
入力の検証によく使われます:
int num;
do {
printf("Enter a positive number: ");
scanf("%d", &num);
} while (num <= 0);
printf("You entered: %d\n", num);
ユーザーが正しい入力をするまで、繰り返し入力を求めます。
---
6.5 break文
ループを途中で抜ける
break を使うと、ループを即座に終了できます。
for (int i = 1; i <= 10; i++) {
if (i == 5) {
break; // i が 5 になったらループを抜ける
}
printf("%d\n", i);
}
printf("Loop ended.\n");
出力:
1
2
3
4
Loop ended.
i が 5 になった時点で break が実行され、ループを抜けます。
検索の例
#include <stdio.h>
int main(void)
{
int numbers[] = {10, 25, 8, 42, 17, 33};
int target = 42;
int found = 0;
for (int i = 0; i < 6; i++) {
if (numbers[i] == target) {
printf("Found %d at index %d\n", target, i);
found = 1;
break; // 見つかったらループを抜ける
}
}
if (!found) {
printf("%d not found\n", target);
}
return 0;
}
---
6.6 continue文
残りの処理をスキップ
continue を使うと、現在のループの残りの処理をスキップし、次の繰り返しに進みます。
for (int i = 1; i <= 5; i++) {
if (i == 3) {
continue; // i が 3 のときはスキップ
}
printf("%d\n", i);
}
出力:
1
2
4
5
i が 3 のとき、continue により printf がスキップされます。
偶数のみ表示
for (int i = 1; i <= 10; i++) {
if (i % 2 != 0) {
continue; // 奇数はスキップ
}
printf("%d\n", i);
}
出力:
2
4
6
8
10
breakとcontinueの違い
// break: ループ全体を終了
for (int i = 1; i <= 5; i++) {
if (i == 3) break;
printf("%d ", i);
}
// 出力: 1 2
// continue: 現在の繰り返しのみスキップ
for (int i = 1; i <= 5; i++) {
if (i == 3) continue;
printf("%d ", i);
}
// 出力: 1 2 4 5
---
6.7 無限ループ
意図的な無限ループ
条件が常に真になるループは無限ループです。
while (1) {
// 永遠に実行される
}
for (;;) {
// 永遠に実行される
}
無限ループは break と組み合わせて使います:
while (1) {
char input;
printf("Continue? (y/n): ");
scanf(" %c", &input);
if (input == 'n' || input == 'N') {
break;
}
printf("Processing...\n");
}
意図しない無限ループ
無限ループはバグの原因にもなります:
// バグ!カウンターが更新されていない
int i = 0;
while (i < 10) {
printf("%d\n", i);
// i++ を忘れた
}
// バグ!条件が常に真
for (int i = 0; i >= 0; i++) {
printf("%d\n", i);
}
無限ループに陥ったら、Ctrl + C でプログラムを強制終了できます。
---
6.8 ネストしたループ
ループの中にループ
ループの中に別のループを入れることをネスト(入れ子)と呼びます。
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
printf("i=%d, j=%d\n", i, j);
}
}
出力:
i=1, j=1
i=1, j=2
i=1, j=3
i=2, j=1
i=2, j=2
i=2, j=3
i=3, j=1
i=3, j=2
i=3, j=3
外側のループが1回実行されるごとに、内側のループが全回数実行されます。
九九の表
#include <stdio.h>
int main(void)
{
for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= 9; j++) {
printf("%3d", i * j);
}
printf("\n");
}
return 0;
}
出力:
1 2 3 4 5 6 7 8 9
2 4 6 8 10 12 14 16 18
3 6 9 12 15 18 21 24 27
4 8 12 16 20 24 28 32 36
5 10 15 20 25 30 35 40 45
6 12 18 24 30 36 42 48 54
7 14 21 28 35 42 49 56 63
8 16 24 32 40 48 56 64 72
9 18 27 36 45 54 63 72 81
三角形の描画
#include <stdio.h>
int main(void)
{
int height = 5;
for (int i = 1; i <= height; i++) {
for (int j = 0; j < i; j++) {
printf("*");
}
printf("\n");
}
return 0;
}
出力:
*
**
***
****
*****
ネストしたループとbreak
ネストしたループで break を使うと、内側のループだけが終了します。
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (j == 1) {
break; // 内側のループだけを抜ける
}
printf("i=%d, j=%d\n", i, j);
}
}
出力:
i=0, j=0
i=1, j=0
i=2, j=0
外側のループも抜けたい場合は、フラグ変数を使うか、goto を使います(一般的にはフラグ変数が推奨)。
---
6.9 実践:素数判定
素数とは
1と自分自身以外に約数を持たない、1より大きい自然数。
2, 3, 5, 7, 11, 13, 17, 19, 23, ...
実装
#include <stdio.h>
int main(void)
{
int num;
printf("Enter a positive integer: ");
scanf("%d", &num);
if (num <= 1) {
printf("%d is not a prime number.\n", num);
return 0;
}
int is_prime = 1; // 素数と仮定
for (int i = 2; i * i <= num; i++) {
if (num % i == 0) {
is_prime = 0; // 割り切れたら素数ではない
break;
}
}
if (is_prime) {
printf("%d is a prime number.\n", num);
} else {
printf("%d is not a prime number.\n", num);
}
return 0;
}
なぜ i i <= num なのか
約数はペアで存在します。例えば 36 の場合:
- 1 × 36
- 2 × 18
- 3 × 12
- 4 × 9
- 6 × 6
6 以上の約数を調べる必要はありません(すでにペアとして見つかっている)。つまり、平方根までチェックすれば十分です。
i <= sqrt(num) よりも i i <= num の方がライブラリ不要で効率的です。
---
6.10 実践:FizzBuzz
問題
1から100までの数を表示する。ただし:
- 3の倍数のときは "Fizz"
- 5の倍数のときは "Buzz"
- 3と5の両方の倍数のときは "FizzBuzz"
実装
#include <stdio.h>
int main(void)
{
for (int i = 1; i <= 100; i++) {
if (i % 3 == 0 && i % 5 == 0) {
printf("FizzBuzz\n");
} else if (i % 3 == 0) {
printf("Fizz\n");
} else if (i % 5 == 0) {
printf("Buzz\n");
} else {
printf("%d\n", i);
}
}
return 0;
}
出力(一部)
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
...
FizzBuzzは、プログラマーの採用面接でよく出される問題です。単純そうに見えて、意外と間違える人が多いです。
---
6.11 この章のまとめ
学んだこと
- for文
- do-while文
- break
- continue
- 無限ループ
while(1) または for(;;)
- break と組み合わせて使用- ネストしたループ
ループの選び方
| 状況 | 推奨するループ | |------|----------------| | 回数が決まっている | for | | 条件が満たされるまで | while | | 最低1回は実行したい | do-while | | 途中で抜ける可能性 | while + break |
次の章の予告
次章では、関数を学びます。処理をまとめて再利用する方法を覚えましょう。
---
Column: ループの名前の由来
for, while, do の語源
プログラミング言語のキーワードは、英語の単語から来ています。
- for: 「〜の間」「〜のために」
- while: 「〜の間」
- do: 「する」「行う」
これらの言葉は1960年代のALGOLという言語で導入され、C言語を経て、現代のほとんどの言語に受け継がれています。
goto とスパゲッティコード
昔のプログラミング言語には goto 文しかありませんでした。
// 昔のスタイル(推奨されない)
int i = 0;
loop:
if (i >= 10) goto end;
printf("%d\n", i);
i++;
goto loop;
end:
printf("Done\n");
このように goto を多用すると、コードがスパゲッティのように絡まり合い、読みにくくなります。
構造化されたループ(for, while, do-while)の登場により、コードははるかに読みやすくなりました。
// 現代のスタイル
for (int i = 0; i < 10; i++) {
printf("%d\n", i);
}
printf("Done\n");
---
確認問題
問題1
以下のコードの出力は何ですか?for (int i = 0; i < 5; i++) {
printf("%d ", i);
}
解答
0 1 2 3 4
i は 0 から始まり、5 未満の間(0, 1, 2, 3, 4)繰り返す。
問題2
以下のwhileループをfor文に書き換えてください。int i = 10;
while (i >= 0) {
printf("%d ", i);
i--;
}
解答
for (int i = 10; i >= 0; i--) {
printf("%d ", i);
}
問題3
以下のコードの出力は何ですか?for (int i = 0; i < 5; i++) {
if (i == 2) continue;
if (i == 4) break;
printf("%d ", i);
}
解答
0 1 3
- i=0: 表示
- i=1: 表示
- i=2:
continueでスキップ - i=3: 表示
- i=4:
breakでループ終了
問題4
1から100までの整数の合計を計算するプログラムを書いてください。解答
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
}
printf("Sum: %d\n", sum); // Sum: 5050
問題5
5段の逆三角形を描画するプログラムを書いてください。*****
****
***
**
*
解答
for (int i = 5; i >= 1; i--) {
for (int j = 0; j < i; j++) {
printf("*");
}
printf("\n");
}
---
次の章では、関数を学びます。コードを整理し、再利用する技術を身につけましょう!