C言語超入門④ while文とfor文で繰り返そう
while、for、do-while、break、continueを使い、同じ処理を安全に繰り返す方法を学びます。
1から100まで表示したいとき、printfを100回書くのはつらいですよね。そこで使うのがループ(繰り返し)です。
ただ短く書くためだけではありません。「人数分のデータを読む」「正しい値が来るまで質問する」といった処理を、同じ考え方で作れるようになります。
今回はwhile、for、do-whileを順に比べます。if文の条件が読めれば始められます。短い例は、stdio.hを読み込んだプログラムのmain内で試してください。
1. whileは「条件を確認してから、もう1回」
#include <stdio.h>
int main(void) {
int number = 1;
while (number <= 3) {
printf("%d\n", number);
number++;
}
printf("終了時: %d\n", number);
return 0;
}
1
2
3
終了時: 4
number++は、ここではnumber = number + 1と同じく1増やす操作です。ループは次の順番で進みます。
| 条件を見るときのnumber | number <= 3 |
本体で行うこと |
|---|---|---|
| 1 | 真 | 1を表示し、2へ更新 |
| 2 | 真 | 2を表示し、3へ更新 |
| 3 | 真 | 3を表示し、4へ更新 |
| 4 | 偽 | 本体へ入らず終了 |
最後の条件確認も数えると4回ですが、本体の実行は3回です。「何回表示したか」と「何回条件を調べたか」は同じとは限りません。
最初からnumber = 4なら、本体は一度も実行されません。whileは0回で終わる可能性がある繰り返しです。
2. 無限ループは「条件が変わるか」で見つける
先ほどのnumber++を消すと、numberはずっと1です。条件が真のままなので、1を表示し続けます。
こうした終わらない繰り返しを無限ループと呼びます。意図的に使う場面もありますが、今回の表示では間違いです。うっかり実行した場合は、ターミナルの停止操作、一般的にはCtrl+Cで止めます。
書くときは次の3点を言葉にしてみましょう。
- 最初の値は何か
- 何が変わって次へ進むか
- どの状態で条件が偽になるか
また、while (number <= 3);のように条件の直後へ;を置くと、何もしない処理を繰り返してしまいます。字下げだけでなく、{ }と;の位置を見ます。
3. forは繰り返しの準備を1か所にまとめる
for (int i = 1; i <= 3; i++) {
printf("%d\n", i);
}
表示は先ほどと同じ1、2、3です。丸かっこの中をセミコロンで3つに分けています。
int i = 1:最初に1回だけ行う準備i <= 3:本体の前に確認する条件i++:本体を実行した後の更新
文字の並びは「準備・条件・更新」ですが、実行する順は「準備 → 条件 → 本体 → 更新 → 条件」です。更新を先にしてから表示するわけではありません。
iは回数や位置に使う短い変数名です。意味が大切な場面ならdayやstudentIndexのような名前でも構いません。
0から始めるなら、条件も合わせる
for (int i = 0; i < 3; i++) {
printf("%d回目\n", i + 1);
}
内部のiは0、1、2。表示は1、2、3回目です。3回繰り返したいからといってi <= 3にすると、0も含めて4回になります。
この1回のずれはオフバイワンエラーと呼ばれます。次回以降の配列では範囲外アクセスにつながるので、「最初と最後に本体へ入る値」を書き出す癖を付けておくと助かります。
4. 繰り返すたびに合計を育てる
int total = 0;
for (int i = 1; i <= 4; i++) {
total = total + i;
}
printf("合計: %d\n", total);
結果は10です。
| 足す数i | 足す前のtotal | 足した後のtotal |
|---|---|---|
| 1 | 0 | 1 |
| 2 | 1 | 3 |
| 3 | 3 | 6 |
| 4 | 6 | 10 |
totalは「これまでの合計」を覚える変数です。total += iと短く書くこともできます。
int total = 0;をループの中へ移すと、毎回0に戻ってしまいます。合計のように次の回へ持ち越す値は、外で準備しましょう。
また、totalを表示する行がループの中なら途中経過を毎回、外なら最後の結果を1回だけ表示します。置く場所によって目的が変わります。
5. do-whileは「まず1回やってから確認」
#include <stdio.h>
int main(void) {
int number = 0;
do {
printf("1から10の整数: ");
if (scanf("%3d", &number) != 1) {
printf("数字として読めないため終了します。\n");
return 1;
}
} while (number < 1 || number > 10);
printf("%dを受け取りました。\n", number);
return 0;
}
0、12、5の順に入力すると、最初の2つではもう一度質問し、5で抜けます。条件が後ろなので、質問は最低1回行われます。
最後のwhile (...);にはセミコロンが必要です。普通のwhileの直後に付けるのとは場所が違います。
この例は短い整数の練習用で、先頭の数値だけを読む場合があります。abcのように読めない入力では再試行せず終了します。同じ入力が残ったままscanfを繰り返すと、入力待ちにならず失敗し続けるためです。
文字を断って再入力できる仕組みは、成績管理の回で1行ずつ読み取る方法として扱います。
6. breakとcontinueはどこへ進む?
breakはループの外へ
for (int i = 1; i <= 10; i++) {
if (i == 5) {
break;
}
printf("%d\n", i);
}
表示は1、2、3、4。5になると表示する前に抜けます。
breakが抜けるのは、最も内側のループまたはswitchです。二重ループの外側までまとめて抜ける命令ではありません。
continueはその回の残りを飛ばす
for (int i = 1; i <= 5; i++) {
if (i == 3) {
continue;
}
printf("%d\n", i);
}
表示は1、2、4、5です。3の回だけ表示を飛ばし、i++へ進みます。
whileでcontinueを使う場合は、次に条件確認へ戻ります。更新処理がcontinueより下にあると、その更新が飛ばされて無限ループになることがあります。迷ったら、最初はifの中へ必要な処理だけを書く形でも十分です。
繰り返しとジャンプの規則は、C11公開委員会草案の6.8.5と6.8.6に定義されています。
7. 練習:1から100のうち3の倍数を表示しよう
まず1から100までの数を順に見て、3で割り切れるときだけ表示してください。
模範解答
#include <stdio.h>
int main(void) {
for (int number = 1; number <= 100; number++) {
if (number % 3 == 0) {
printf("%d\n", number);
}
}
return 0;
}
解説
%は余りを求める記号です。3で割った余りが0なら3の倍数なので、ifの中で表示します。
1と2は飛ばし、3で最初の表示。最後は99で、100は条件に当てはまらないので表示されません。期待する個数は33個です。
別解としてfor (int number = 3; number <= 100; number += 3)なら、3、6、9と必要な数だけ進められます。最初の解答は「すべてを調べて選ぶ」、別解は「対象だけを作る」という違いです。
次の一歩
回数が見えているならfor、回数より終了条件を表したいならwhile、質問などを最低1回行うならdo-whileが候補です。どれが一番上等、という関係ではありません。
まず3回程度の小さな例で値を追ってから、大きな回数へ変えると、何が起きているか見失いにくくなります。