さまざまなデータ処理プログラムを作りながら, 反復制御(for,while,do-while)について理解しよう.
条件式は if 文と共通.
ソースコード記述方法:
int カウンタ; // 反復回数を入れるよ for (カウンタの初期化; 反復条件; カウント) { 繰り返したい処理 }
例1:カウントアップ(0 から 9 まで数える)
int i; for (i = 0; i < 10; i++) { printf("%d\n", i); }
動作:カウンタを初期化 i = 0 する. 反復条件 i < 10 が成立しているので, printf() を実行し,「0」を表示する. カウントアップ i++ により i = 1 とし, 反復条件へ戻る.
なぜ 10 を使うのか?0 から 9 までの 10 回なので. (もちろん,条件式を i <= 9 としてもよい.)
なお,i++ は i = i + 1 の短縮版ね. (実は,微妙に違いますが,今は気にしないでおく.)
そして,このループの終了後,カウンタ i の値は 9 ではなく, 10 になっていることに注意しよう.
例2:カウントダウン(9 から 0 まで数える)
int i; for (i = 9; i >= 0; i--) { printf("%d\n", i); }
ここで,i-- は i = i - 1 の短縮版ね.(同上.)
ソースコード記述方法:
while (反復条件) { 繰り返したい処理 }
動作:最初に反復条件を計算する. もし成立していたらブロック { } 内を処理し while へ戻る.
特殊な反復条件:
ソースコード記述方法:
do { 繰り返したい処理 } while (反復条件);
動作:最初にブロック { } 内を処理し,次に反復条件を計算する. もし成立していたら,do へ戻る.
反復回数に応じて...
いつもの通り,作業用ディレクトリを準備しよう:
$ cd $ mkdir c-0523 $ cd c-0523
複数の非負整数データを合計するプログラム total.c を 3種類のループで作り分けてみる.
$ vim total.c # エディタは何でも OK
#include <stdio.h> int main(void) { int total = 0; // 合計 int x; // データ int n, i; // データの個数,カウンタ // データの個数の入力 printf("データの個数 > "); scanf("%d", &n); // 個数を入力 // データの入力,合計の計算 printf("%d 個の非負整数 > ", n); for (i = 0; i < n; i++) { scanf("%d", &x); // データを入力 total += x; // 合計を加算,total = total + x; } // 結果の表示 printf("合計 = %d\n", total); return (0); }
$ cc total.c -o total $ ./total データの個数 > 5 3 個の非負整数 > 1 2 3 4 5 合計 = 15
個数の入力が面倒くさいですね. データが何個あるか入力前に数えておく必要があるなんて, 実用的ではない. for だと,個数を最初に決めておかなければならないので... while を使って書き換えてみよう.
... int main(void) { int total = 0; int x;/* int n, i; // データの個数の入力 printf("データの個数 > "); scanf("%d", &n); */// データの入力,合計の計算 printf("複数個の非負整数(最後に -1)> "); x = 0; // 初回の反復条件を成立させるための措置 while (x >= 0) { scanf("%d", &x); total += x; } total -= x; // 調整(最後の x = -1 は合計すべきデータではない) // 結果の表示 ... }
... $ ./total 複数個の非負整数 > 1 2 3 4 5 -1 合計 = 15
データ数が多い場合を考えれば, 使い勝手は for 版よりは良くなったよね?
しかし,調整の処理が(正しく計算するために必要ではあるが) 無駄手間(足してから引いている)となっている. データ入力と合計計算の順序を交換すれば この調整処理は不要となる.改善版:
x = 0; while (x >= 0) { total += x; scanf("%d", &x); }// total -= x;
さらに,この処理手順の場合, 必ず1回以上はループ内の入力 scanf() が実行されるので, do-while の方が適切だ.
... int main(void) { ... // データの入力,合計の計算 printf("複数個の非負整数(最後に -1)> "); x = 0; do { total += x; scanf("%d", &x); } while (x >= 0); // 結果の表示 ... }
ソースコード的は while 版とほとんど変わりないが, 入力終了時にブロックの上方向へ戻る必要がなく, 処理手順的には,より効率的だ. しかし,まだ入力前の合計計算という不自然と無駄は残っている. (この辺りの問題点については,次回に解決予定.)
掛け算を足し算の反復で計算してみよう. mul.c:
#include <stdio.h> int main(void) { int x, y, z; // x * y = z int i; // カウンタ printf("非負整数 x, y >; // 問題を入力 scanf("%d %d", &x, &y); z = 0; // 反復回数は既知なので for文 for (i = 0; i < y; i++) { // y 回繰り返す z = z + x; // x を足す } printf("%d * %d = %d\n", x, y, z); // 計算結果を表示 return (0); }
考え方のヒント:x*y = x + x + x + ... = (((0 + x) + x) + x) + ... それぞれの括弧がループ1回分, 括弧内の計算結果が z ね.
割り算を引き算の反復で計算してみよう. ついでに剰余(余り)も計算するよ. div.c:
#include <stdio.h> int main(void) { int x, y, z; // x / y = z int m; // 剰余 m = x % y printf("自然数 x, y > "); // 問題を入力 scanf("%d %d", &x, &y); z = 0; m = x; // 反復回数は未知(割り算の結果)だしゼロかもしれないので while文 while (m >= y) { // 引き算できるだけ反復 m = m - y; // x から y を引く z++; // 引き算の回数をカウント } printf("%d / %d = %d ... %d", x, y, z, m); // 計算結果を表示 return (0); }
考え方のヒント:引き算できた回数が計算結果となる.
要求仕様:非負整数 n の数値を入力データとする.
要求仕様:整数 0〜100 を入力データとする. (余裕ある人はこの条件を無視してハードルを上げてみよう. どんな整数でもよいことにする. 最初のデータを最大値・最小値の初期値とすればよい. 終了方法には工夫とか妥協が必要かも.)
提出: