Menu

C#のwhile文とdo while文:構文、入力ループ、落とし穴

C#のwhileループとdo-whileループの動き方を解説します。本体の前か後で確認される条件、番兵や入力の終わりまでの読み込み、breakを使うwhile (true)、そしてつまずきやすい無限ループの間違いを扱います。

このページのコードはエディタで実行できます - 編集してすぐに結果を確認できます。

while ループは、条件が真である限り本体を繰り返します。残高が目標に届くまで、キューが空になるまで、入力がなくなるまでというように、必要な反復回数が事前にわからないときに使います。

出力:

Year 1: 1070.00
Year 2: 1144.90
Year 3: 1225.04
Year 4: 1310.80
Year 5: 1402.55
Year 6: 1500.73
Goal reached after 6 years

条件は最初を含めて各反復の前に確認されます。savings がすでに目標に達していれば、本体は一度も実行されず、プログラムは「after 0 years」と表示します。ループは、条件が読む何かを本体が変えることに依存しています。ここでは savings が毎年増え、やがて savings < goal がfalseになります。

do while:少なくとも1回実行する

do while ループは判定を末尾に移すので、本体は常に少なくとも1回実行されます。

出力:

Attempt 1: got 7
Attempt 2: got 4
Attempt 3: got 1
Done after 3 attempts

code の最初の値は本体が1回実行された後にしか存在しません。まさに do while が合う場面です。構文上の注意点が2つあります。

  • while (code != 1) の後のセミコロンは必須です。省くとコンパイルエラーになります。
  • 条件で使う変数は do の前に宣言しなければなりません。波かっこの中で宣言した変数は条件が実行される時点でスコープの外にあるので、do { int code = ...; } while (code != 1); はコンパイルできません。

同じループを while で書くと、ループの前で最初の呼び出しを重複させるか、最初の実行を強制するためのダミーの初期値が必要になります。do while は「試してから、もう一度試すか決める」をそのまま表現します。

番兵まで入力を読み込む

停止を表す単語まで、または入力が終わるまで行を読み込むのは、教科書どおりの while ループです。Console.ReadLine() は入力がなくなると null を返すので、両方を判定します。

出力:

skipping "abc": not a number
3 amounts, total 49.50

(line = Console.ReadLine()) != null は1つの式の中で次の行を代入して判定します。!= は = より優先順位が高いので、代入を囲むかっこは必須です。ループは done で止まるので、その後の 99 は読まれません。decimal.TryParse は例外を投げずに abc を拒否し、continue が次の行に進みます。null のチェックがないと、ReadLine は null を返し続けるので、入力の終わりに達した後は TryParse に null を永遠に渡し続けます。

do while は、入力を促して検証する形に向いています。この形では促すメッセージが少なくとも1回は表示されなければなりません。

出力:

Enter your age:
"-4" is not a valid age
Enter your age:
"fifteen" is not a valid age
Enter your age:
Age accepted: 15

促すメッセージはループの中にあるので、拒否された回答のたびに繰り返され、age は do の前に宣言されているのでループの後のコードで使えます。キーボードの前にユーザーがいる場合は、各回答がメッセージの後にコンソールに表示されます。ここのように入力をリダイレクトした場合は、プログラム自身の出力だけが表示されます。

breakを使うwhile (true)

本体の途中、つまりある処理の後で残りの処理の前が、自然な終了地点になることがあります。ループを while (true) と書き、break で抜けます。

出力:

processing: resize photo
processing: send email
stop signal received
1 job(s) left in the queue

Dequeue は キュー の先頭から次のジョブを取り出し、ループは停止の目印を見た時点で抜けるので、最後のジョブはキューに残ります。終了条件が明確で本体の先頭近くにあるなら、while (true) は悪いコードの兆候ではありません。長い本体のあちこちに break が散らばっていると、そうなります。その場合は名前の付いた bool の条件か、return するメソッドのほうが追いやすくなります。ネストしたループから抜ける方法はbreakとcontinueのページで扱います。

終わらないループ

意図しない無限ループの原因は、次の3つのいずれかです。

本体が条件を変えていない。 カウンターを増やしていないか、別の変数を増やしています。

int i = 0;
while (i < 5)
{
    Console.WriteLine(i);   // i++ forgotten: prints 0 forever
}

条件の後のセミコロン。 セミコロンがループの本体全体になり、その下のブロックはループの後で実行されます(ループは終わりませんが)。

while (retries < 3);        // warning CS0642: Possible mistaken empty statement
{
    retries++;
}

目標を飛び越える条件。 変数が一定の幅で動くときに != で判定すると、停止する値を飛び越えることがあります。while (x != 10) x += 3; は0、3、6、9、12と進み、10をそのまま通り過ぎます(何十億ステップ後に int がオーバーフローして一周し、偶然10に着地したときにだけ止まります)。増分が1でないときは、!= ではなく < や > で判定します。同じことは、正確な目標値にめったに一致しない double の値にも当てはまります:while (x != 1.0) x += 0.1; は終わりません。

while、do while、forの選び方

状況ループ
反復回数がわかっている、またはインデックスを使うfor
コレクションのすべての要素foreach
条件が成り立つ間繰り返す(0回もありうる)while
条件が意味を持つ前に本体を1回実行する必要があるdo while
終了判定が本体の途中にあるbreak を使う while (true)

どの for ループも while ループに書き換えられ、その逆もできます。選択の基準は、ループの論理を読む人が期待する場所に置けるのはどちらか、です。カウンター、判定、増分がすべてそろっているなら、for はそれらを1行にまとめます。本体の中で変わる状態がループを動かしているなら、while がそれをそのまま表します。

よくある質問

C#のwhileとdo whileの違いは何ですか?

while ループは各反復の前に条件を確認するので、本体が1回も実行されないことがあります。do { } while (condition); ループは各反復の後に確認するので、本体は常に少なくとも1回実行されます。入力を読んでから検証するように、最初の実行で条件が判定する値が生まれる場合は do while を使います。

C#のdo whileループの構文は?

do { body } while (condition); です。閉じかっこの後のセミコロンに注意してください。必須で、省くとコンパイルエラーになります。条件では本体で代入した変数を使えますが、本体の波かっこは別のスコープなので、それらの変数は do の前に宣言しておく必要があります。

C#でwhile (true)はどう書きますか?

while (true) { ... } は、中の何かが break、return、例外で抜け出すまで永遠に繰り返します。1行読んで空なら止めるなど、終了判定が本体の途中にあるときに自然な形です。

C#でユーザーが特定の単語を入力するか入力が終わるまで読み込むには?

入力の終わりで null を返す Console.ReadLine() でループします:string line; while ((line = Console.ReadLine()) != null && line != "done") { ... }。条件の中の代入が、次の行の読み込みと判定を1ステップで行います。

C#のwhileループが終わらないのはなぜですか?

たいていは、本体が条件の判定対象を変えていない(i++ の書き忘れ)か、条件の直後にセミコロンがあるかのどちらかです。while (count < 10); は本体が空のループで、永遠に回り続けます。2つ目のケースについて、コンパイラはCS0642 Possible mistaken empty statement で警告します。

Coddy programming languages illustration

Coddyでコードを学ぼう

始める