C言語のwhile
文は、「条件が真の間だけ本体を繰り返す」ための基本構文です。
for文より自由度が高く、入力の読み取りや状態待ち、無限ループなど幅広く使えます。
本記事では、構文と評価タイミング、実用例、break
/continue
の基礎、そして落とし穴と対策まで、初心者の方にも順を追って詳しく解説します。
C言語のwhile文の基本
while文の構文と評価タイミング
while文は「前判定(ループに入る前に条件を評価)」のループです。
最初の判定で偽なら1回も実行されません。
基本の構文
/*
while(条件式) が真(0以外)の間、本体を繰り返します。
条件はループの先頭で毎回評価されます。
*/
while (/* 条件式 */) {
/* 繰り返したい処理 */
/* ループ継続のための更新(カウンタの増減など) */
}
評価タイミングのイメージ
次の順で進みます。
「条件→本体→更新→条件…」の繰り返しです。
- 初期化(ループの外)
- 条件式を評価
- 条件が真なら本体を実行
- ループ継続に必要な更新を行う
- 再び条件を評価
条件式の真偽(0と0以外)
C言語では0が偽、0以外が真として扱われます。
真偽値用の専用型を使わなくても、整数の0/非0で制御できます。
0と非0の例(0になるまでカウントダウン)
#include <stdio.h>
int main(void) {
int v = 3; // 0以外なので真 → ループに入る
while (v) { // vが0になるまで繰り返す
printf("v = %d\n", v);
v = v - 1; // 更新: 1ずつ減らす
}
printf("ループ終了(vは0)\n");
return 0;
}
v = 3
v = 2
v = 1
ループ終了(vは0)
変数の初期化と更新の置き場所
初期化はループの外、更新はループの内側が基本です。
更新を忘れると条件が変わらず無限ループになります。
初期化と更新の位置
#include <stdio.h>
int main(void) {
int i = 0; // 初期化は外
while (i < 5) { // 条件は先頭で判定
printf("%d ", i);
i = i + 1; // 更新は内側(忘れないように!)
}
printf("\n");
return 0;
}
0 1 2 3 4
whileループの基本フロー
典型的なwhileの流れは次の通りです。
処理を順に分解すると読みやすく安全に書けます。
- 準備(初期化)
- 条件式の評価
- 本体の処理
- 継続に必要な更新
- 終了条件を満たすまで繰り返し
以下の表は位置づけの目安です。
役割 | 置き場所 | 例 |
---|---|---|
初期化 | ループの外 | int i = 0; |
条件 | whileのカッコ内 | i < 10 |
本体 | 中かっこ内 | printfなどの主処理 |
更新 | 本体の最後付近 | i = i + 1; |
while文の使い方と例
カウンタで回すwhileの例
決まった上限まで回すときの最小パターンです。
増分はi = i + 1
のように明示的に書くと初心者には分かりやすいです。
1から5まで表示
#include <stdio.h>
int main(void) {
int i = 1; // 初期化
while (i <= 5) { // 条件
printf("%d ", i); // 本体
i = i + 1; // 更新
}
printf("\n");
return 0;
}
1 2 3 4 5
入力を読み続けるwhile(scanfとEOF)
件数が分からない入力を最後(EOF)まで読み続ける用途に相性が抜群です。
scanf
は読み取れた項目数を返し、EOF
に達すると負の値を返します。
整数を読み続けて合計する
#include <stdio.h>
int main(void) {
int x;
long long sum = 0;
// 整数が1個読めた間だけ繰り返す
// 読めない(EOFや不正入力)と while が終わる
while (scanf("%d", &x) == 1) {
sum = sum + x;
}
printf("合計: %lld\n", sum);
return 0;
}
入力例:
10 20
-5
15
^D
合計: 40
端末からのEOFは、UNIX系ではCtrl+D、Windowsの一部環境ではCtrl+Z(Enter)で送ります。
条件が整うまで待つwhile(フラグ制御)
フラグが立つまで待機し、条件が満たされたら先へ進む書き方です。
実環境ではI/Oの準備完了などの待機に使います。
フラグが0の間は待機メッセージを表示
#include <stdio.h>
int main(void) {
int ready = 0;
int ticks = 0;
// readyが1になるまで待つ(ここでは3回目で準備完了にする)
while (ready == 0) {
printf("準備中... (tick = %d)\n", ticks);
ticks = ticks + 1;
if (ticks >= 3) { // 条件が整ったとみなす
ready = 1;
}
}
printf("開始します。\n");
return 0;
}
準備中... (tick = 0)
準備中... (tick = 1)
準備中... (tick = 2)
開始します。
実際の待機でCPUを占有し続けるのは非効率です。
現実のプログラムではスリープやイベント待ちを組み合わせます。
無限ループ(while(1))の書き方と注意
無限に回すにはwhile(1)
を使います。
必ず終了条件とbreak
などの脱出手段を用意しましょう。
カウンタが一定に達したらbreakで抜ける
#include <stdio.h>
int main(void) {
int count = 0;
while (1) { // 無限ループ
printf("count = %d\n", count);
if (count >= 3) { // 終了条件
break; // ここで脱出
}
count = count + 1; // 更新
}
printf("ループ終了\n");
return 0;
}
count = 0
count = 1
count = 2
count = 3
ループ終了
注意: 何も待たずに高速で回り続ける無限ループはCPUを占有します。
必要に応じて待機(スリープ)やI/O待ちを入れてください。
whileで使うbreakとcontinue
breakでループを抜ける基本
特定の条件で直ちにループ全体を抜けるのがbreak
です。
5で止める例
#include <stdio.h>
int main(void) {
int i = 1;
while (i <= 10) {
if (i == 5) {
break; // iが5ならループ終了
}
printf("%d ", i);
i = i + 1;
}
printf("\n抜けました(i == %d)\n", i);
return 0;
}
1 2 3 4
抜けました(i == 5)
continueで1回分の処理をスキップ
continue
は現在の反復の残りを飛ばし、次回の条件判定へ進むための文です。
3の倍数だけスキップ
#include <stdio.h>
int main(void) {
int i = 1;
while (i <= 10) {
if (i % 3 == 0) { // 3の倍数
i = i + 1; // 更新を忘れない!
continue; // この回の処理をスキップ
}
printf("%d ", i);
i = i + 1;
}
printf("\n");
return 0;
}
1 2 4 5 7 8 10
ネストしたwhileでのbreakとcontinueの挙動
break/continueは「今いる一番内側のループ」に作用します。
外側には直接効きません。
内側のみを抜ける/スキップする例
#include <stdio.h>
int main(void) {
int outer = 1;
while (outer <= 2) { // 外側
int inner = 1;
while (inner <= 4) { // 内側
if (inner == 2) {
inner = inner + 1;
continue; // 内側の2をスキップ
}
if (inner == 4) {
break; // 内側だけを抜ける
}
printf("(o=%d,i=%d) ", outer, inner);
inner = inner + 1;
}
printf("| 内側終了 o=%d\n", outer);
outer = outer + 1;
}
return 0;
}
(o=1,i=1) (o=1,i=3) | 内側終了 o=1
(o=2,i=1) (o=2,i=3) | 内側終了 o=2
breakが効く範囲(内側のwhileのみ)
breakは内側の1ループだけを終了させます。
外側まで一気に抜けたい場合は、フラグを立てる、関数を抜ける(return
)、または設計を見直すなどで対処します。
文 | 影響範囲 | メモ |
---|---|---|
break | 直近の内側ループのみ | 多重ループで外側には効かない |
continue | 直近の内側ループの次回判定へ | 更新忘れに注意 |
while文の注意点とベストプラクティス
更新忘れによる無限ループを防ぐ
更新漏れは最頻出のバグです。
条件が変化しないと永遠に真のままになります。
更新は本体の末尾にまとめる、コメントで意識づけする、テスト時に小さな回数で試すなどの工夫をしましょう。
// 悪い例: iの更新がないため無限ループ
while (i < 10) {
printf("%d\n", i);
// i = i + 1; がない!
}
セミコロンの置き間違い(while直後)
whileの直後に誤ってセミコロンを書くと、空ループになり、意図しない動作をします。
// 悪い例: 空ループになる
while (i < 3); { // ← このセミコロンが余計
printf("実はここは1回だけ実行\n");
}
// 良い例: セミコロンは付けない
while (i < 3) {
printf("正しく繰り返し\n");
i = i + 1;
}
代入(=)と比較(==)の取り違え
致命的なバグです。
=
は代入、==
は比較です。
// 悪い例: 代入になってしまい常に真(1) → 無限ループ
while (flag = 1) { // 本当は flag == 1 と書きたかった
/* ... */
break; // 例のために強制脱出
}
// 良い例: 比較は==で
while (flag == 1) {
/* ... */
}
対策: 警告を最大化する(-Wall -Wextra
)、条件を左に定数(例: 1 == flag
)で書くスタイルを採用する、レビューで着目する。
読みやすい条件式に分解するコツ
長い条件は補助変数で意味づけすると理解しやすくなります。
#include <stdio.h>
int main(void) {
int i = 0;
int limit = 100;
int ok_range, ok_even;
while (i <= limit) {
ok_range = (i >= 10) && (i <= 30); // 範囲チェック
ok_even = (i % 2 == 0); // 偶数か
if (ok_range && ok_even) {
printf("%d ", i);
}
i = i + 1;
}
printf("\n");
return 0;
}
10 12 14 16 18 20 22 24 26 28 30
条件に名前を与える、否定(== 0
など)はできるだけ避けて肯定形で書く、比較は左右の単位を揃えると読みやすくなります。
まとめ
while文は「前判定で条件が真の間だけ繰り返す」汎用のループ構文です。
初期化を外、更新を内側に置く基本形を守れば、多くの処理を安全に表現できます。
入力をEOFまで読む、フラグで状態待ちをする、無限ループからbreak
で脱出するなど、実用の幅も広いです。
一方で、更新忘れ・セミコロン誤置・=
/==
取り違えは典型的な落とし穴です。
条件式は分解して意味づけし、警告を活用しながら、意図が明確な読みやすいwhileを書いていきましょう。