C#: ループ構造

1. whileループ

while ループは、その条件が true である限り、コードブロックを繰り返します。条件は各反復の前にチェックされ、false である場合は、ループ本体全体がスキップされます。

CSHARP
int count = 1;
while (count <= 5)
{
    Console.WriteLine($"Execution #{count}");
    count++;
}
TEXT 📖 参照専用
Execution #1
Execution #2
Execution #3
Execution #4
Execution #5

ヒント:条件が最初から false の場合、ループ本体は決して実行されません。


2. do...while ループ

do...while ループは、まず本体を実行し、その後、条件をチェックします。条件の結果にかかわらず、ループ本体は少なくとも 1 回は実行されます。

CSHARP
int number;
do
{
    Console.WriteLine("Enter a positive number:");
    number = int.Parse(Console.ReadLine());
} while (number <= 0);
Console.WriteLine($"You entered: {number}");

警告:do...while の末尾にあるセミコロンは必須です。これは while ループとは構文が異なります。


3. forループ

for ループは、初期化、条件判定、反復処理の更新を1行にまとめることができるため、反復回数があらかじめわかっている場合に最適です。

CSHARP
for (int i = 1; i <= 5; i++)
{
    Console.WriteLine($"i = {i}");
}
TEXT 📖 参照専用
i = 1
i = 2
i = 3
i = 4
i = 5

for ステートメントの 3 つの部分はいずれも省略できますが、セミコロンは残しておく必要があります:

CSHARP
int j = 0;
for (; j < 3; )
{
    Console.WriteLine($"j = {j}");
    j++;
}
TEXT 📖 参照専用
j = 0
j = 1
j = 2

4. foreach ループ

foreach ループは、コレクション内の各要素を反復処理するための C# の機能です。この機能は、簡潔で安全な構文を提供し、配列、リスト、および IEnumerable を実装するあらゆるコレクションで動作します。

CSHARP
string[] fruits = { "Apple", "Banana", "Orange" };
foreach (var fruit in fruits)
{
    Console.WriteLine($"Fruit: {fruit}");
}
TEXT 📖 参照専用
Fruit: Apple
Fruit: Banana
Fruit: Orange

警告:foreach ループは読み取り専用です。反復変数は読み取り専用のコピーです。これを通じてコレクションの要素を変更したり、反復中に要素を追加・削除したりすることはできません。そうすると、InvalidOperationException 例外が発生します。

▶ サンプル

CSHARP
int[] scores = { 90, 85, 72, 60, 95 };
int sum = 0;
foreach (int score in scores)
{
    sum += score;
}
Console.WriteLine($"Total: {sum}, Average: {(double)sum / scores.Length:F1}");
▶ 試してみよう
TEXT 📖 参照専用
Total: 402, Average: 80.4

5. ネストされたループ

ループの中に別のループがあるものを「ネストされたループ」と呼び、行列や表などの2次元データ構造の処理によく用いられます。

CSHARP
for (int row = 1; row <= 3; row++)
{
    for (int col = 1; col <= 4; col++)
    {
        Console.Write($"{row * col,4}");
    }
    Console.WriteLine();
}
TEXT 📖 参照専用
   1   2   3   4
   2   4   6   8
   3   6   9  12

警告:ネストされたループの時間計算量は O(n^2) です。ネストの層が深くなるほど、パフォーマンスは低下します。実際には、深いネストを避け、LINQ の使用やメソッドの抽出による最適化を検討してください。


6. break と continue

(1) 改行

break は、現在のループを直ちに終了し、残りのすべての反復をスキップします。

CSHARP
for (int i = 0; i < 10; i++)
{
    if (i == 5) break;
    Console.Write($"{i} ");
}
TEXT 📖 参照専用
0 1 2 3 4

(2) 続き

continue は、現在の反復処理の残りの部分をスキップして、次の反復処理にジャンプします。

CSHARP
for (int i = 0; i < 6; i++)
{
    if (i % 2 == 0) continue;
    Console.Write($"{i} ");
}
TEXT 📖 参照専用
1 3 5

ヒント:break および continue は、最も内側のループにのみ影響します。複数のループ階層から抜け出すには、フラグ変数またはラベル付き文を使用してください。


7. 一般的なループパターン

(1) 数え方

条件を満たす要素を数える:

CSHARP
int[] data = { 12, 25, 8, 33, 17, 6, 41 };
int count = 0;
foreach (int val in data)
{
    if (val > 20) count++;
}
Console.WriteLine($"Count of values > 20: {count}");
TEXT 📖 参照専用
Count of values > 20: 3

(2) 蓄積パターン

一連の数の和を求めます:

CSHARP
int sum = 0;
for (int i = 1; i <= 100; i++)
{
    sum += i;
}
Console.WriteLine($"Sum of 1 to 100: {sum}");
TEXT 📖 参照専用
Sum of 1 to 100: 5050

(3) 検索パターン

コレクション内の対象要素を検索する:

CSHARP
int[] numbers = { 3, 7, 15, 22, 9, 31 };
int target = 22;
int index = -1;
for (int i = 0; i < numbers.Length; i++)
{
    if (numbers[i] == target)
    {
        index = i;
        break;
    }
}
Console.WriteLine(index >= 0 ? $"Found {target} at index {index}" : "Not found");
TEXT 📖 参照専用
Found 22 at index 3

▶ サンプル

複数のパターンを組み合わせる - 成績分布を集計し、平均を算出する:

CSHARP
int[] scores = { 92, 78, 55, 88, 43, 96, 67, 73, 81, 50 };
int excellent = 0, pass = 0, fail = 0, total = 0;
foreach (int s in scores)
{
    total += s;
    if (s >= 90) excellent++;
    else if (s >= 60) pass++;
    else fail++;
}
double avg = (double)total / scores.Length;
Console.WriteLine($"Excellent: {excellent}, Pass: {pass}, Fail: {fail}");
Console.WriteLine($"Average: {avg:F1}");
▶ 試してみよう
TEXT 📖 参照専用
Excellent: 2, Pass: 5, Fail: 3
Average: 72.3

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

ループ条件が常にtrueである場合、無限ループが発生し、ループが終了しなくなります。一般的な無限ループのパターン:

CSHARP
while (true)
{
}

for (; ; )
{
}

▶ サンプル

無限ループを回避するための終了条件を備えた制御ループ:

CSHARP
Random rnd = new Random();
int attempts = 0;
while (true)
{
    int value = rnd.Next(1, 101);
    attempts++;
    if (value == 42)
    {
        Console.WriteLine($"Got 42 on attempt #{attempts}!");
        break;
    }
    if (attempts > 1000)
    {
        Console.WriteLine("Too many attempts, exiting loop.");
        break;
    }
}
▶ 試してみよう

無限ループを回避するためのガイドライン:

実際には、while (true)break を組み合わせたループパターンは一般的ですが、各分岐に必ず出口があることを確認してください。

❓ よくある質問

Q whiledo...while の違いは何ですか?
A while はまず条件をチェックし、本体を実行しない場合もあります。一方、do...while はまず本体を実行するため、少なくとも1回は実行されます。
Q foreach ループ内でコレクションの要素を変更することはできますか?
A いいえ。反復変数は読み取り専用のコピーであるため、これを変更しても元のコレクションには影響しません。要素を変更する必要がある場合は、インデックスアクセスを使用する for ループを使用してください。
Q break を使って、ネストされた複数のループから抜け出すことはできますか?
A いいえ。break は最も内側のループからのみ抜け出します。複数のループから抜け出すには、フラグ変数を使用するか、内側のループをメソッドとして抽出し、return を使用してください。
Q for (; ; )while (true) には違いがありますか?
A 機能的には同じです。どちらも無限ループを生成します。 while (true) の方が可読性が高く、for (; ; ) は一部の環境ではコンパイラの警告を回避できる場合があります。

📖 まとめ

📝 練習問題

  1. whileループを使用して、値が1000を超えるまで2の累乗を計算し、すべての結果を出力するプログラムを作成してください。
  2. for ループを使用して、上三角行列形式の九九を印刷してください(重複を避けてください)。
  3. 文字列の配数が与えられたとき、foreach を使用して、長さが 5 より大きい文字列がいくつあるかを数えなさい。
  4. do...while を使用して、正しいパスワードが入力されるまでユーザーにパスワードを繰り返し入力させるプログラムを作成してください(正しいパスワードは自分で決めてください)。
  5. 入れ子になった for ループを使用して、1 から 50 までのすべての素数を求めなさい。
  6. forループ内でcontinueを使用し、1から20までのうち、3で割り切れないすべての数を表示してください。
Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%