C言語編 第14章 同じ処理を繰り返す(while文)

この章の概要

この章の概要です。

反復構造

第11章第12章第13章では、 if文や switch文を使った分岐構造について見てきました。 今回から見ていくのは、もう1つの処理の流れの形式である反復構造です。 反復構造は、同じ内容の処理を何度も繰り返す構造で、ループ構造とも呼ばれます。

順次構造、分岐構造、反復構造を併せて、基本制御構造と呼ばれることがあります。 入口と出口が1つずつあれば、順次構造、分岐構造、反復構造の組み合わせでプログラムは表現可能であると言われており、 要するに、この3つの構造を理解すれば、考えの上ではあらゆるプログラムが書けるはずです。

この考え方は、構造化プログラミングと呼ばれるもの(の一部)です。 構造化プログラミング自体は、1960年代に提唱された非常に古いものですが、今でも、プログラミングの基本思想であり続けています。 とりあえず、現状でそこまで深く考える必要はないでしょう。

C言語には、反復構造を表現するために幾つかの方法が用意されています。 この章では、一番単純な while文を取り上げます。

while文

まず、「標準入力から受け取った文字を、改行しながら10回出力する」ことを考えてみます。 反復構造の使い方を知らない現状では、次のように書くしかありません。

#include <stdio.h>

int main(void)
{
	char c;
	char str[20];

	puts( "1文字入力して下さい。" );
	fgets( str, sizeof(str), stdin );
	sscanf( str, "%c", &c );

	/* 10回出力する */
	printf( "%c\n", c );
	printf( "%c\n", c );
	printf( "%c\n", c );
	printf( "%c\n", c );
	printf( "%c\n", c );
	printf( "%c\n", c );
	printf( "%c\n", c );
	printf( "%c\n", c );
	printf( "%c\n", c );
	printf( "%c\n", c );

	return 0;
}

実行結果:

1文字入力して下さい。
y
y
y
y
y
y
y
y
y
y
y

こんなの面倒ですよね。 そういうとたまに「そうでもない。別にコピー&ペーストしていけば 10個くらい・・・」という人がいますが、10回とは限りません。 10000回かも知れないし、「標準入力から受け取った回数分だけ表示」かも知れません。 前者は(無駄な)努力をすれば可能ですが、後者は不可能です。 実際に、入力してもらうまで必要な回数は分からないのですから、プログラムを書く段階ではどうしようもありません。

そこで、反復構造の出番です。 先ほどのプログラムは、while文を利用して次のように書き変えられます。

#include <stdio.h>

int main(void)
{
	char c;
	char str[20];
	int count;

	puts( "1文字入力して下さい。" );
	fgets( str, sizeof(str), stdin );
	sscanf( str, "%c", &c );

	/* 10回出力する */
	count = 0;
	while( count < 10 ){
		printf( "%c\n", c );
		count = count + 1;
	}

	return 0;
}

実行結果:

1文字入力して下さい。
y
y
y
y
y
y
y
y
y
y
y

まず、while文の構造ですが、次のようになっています。

while( 条件式 ){
	ループさせる処理
}

if文のときと同じで、{ } の中が1行だけなら { } は省略できます。 しかし、例によって省略しないことを勧めます。

「条件式」の部分には、「処理を繰り返すのはどんなときか」を記述します。 条件式が偽の場合には、while文全体を終了させて、その後の処理へ進みます。 実行される処理の順序を整理すると、次のようになります。

  1. 「条件式」を調べる。「真」なら2へ。「偽」なら4へ。
  2. 「ループさせる処理」を実行する。3へ。
  3. 「ループさせる処理」が全て終了したら1へ戻る。
  4. while文を終了させて、次の処理へ進む。

したがって、1〜3の部分がループしていることになります。 もし、初めて1に来た時点で、条件式が偽になっている場合は、ループ内の処理は1度も実行されないことになります


さて、では先ほどのサンプルプログラムを確認しておきましょう。 このプログラムの場合、「10回繰り返す」というように、ループさせる回数が定まっています。 この「回数」をうまく表現しなければなりません。

loop( 10 ){} のような構文があれば簡単ですが、少なくともC言語にはありません。

ループ回数を表現するには、それ専用の変数を1つ用意しておき、ここに「今のところ何回ループしたか」を保存しておくのが簡単です。 今回のサンプルなら、変数count を用意しています。 while文に差し掛かる直前で、count の値を 0 にしておき(つまり、今のところ 0回ループした)、 while文の内部の最後のところで count の値を 1 増やしています。

そして、while文の ( ) のところで、「目的の回数に満たない」という意味合いの条件式を書けば、 目的の回数だけループさせることができます。 慣れるまで反対の意味の条件式を書いてしまいがちですが、「処理を繰り返すのはどんなときか」を書くということを意識して下さい。
今回は 「count < 10」という条件式なので、「count の値が 10未満のときはループする」ことになります。 言いかえれば「現在までにループした回数が 10回未満なら、まだ目的の回数に達していないので、まだループさせる」ということになります。

ところで、「10回繰り返す」ことが目的ならば、「count != 10」ではダメなのかという疑問も生まれるでしょう。 それでも正しく動作するし、意味的にも間違っていません。 要するに正解なのですが、一般的には「count != 10」よりも「count < 10」の方が好まれます。
その理由は、「何かの拍子に count の値が 10 を超えてすり抜けてしまうかも知れない」という不安への対処のためです。 count の値が必ず1ずつ増加しているなら、そんなことはあり得ないのですが、3ずつ増加するように変わったとしたらどうでしょう。 count の取り得る値は「0、3、6、9、12…」と続きますから、決して 10 にはなりません。 そうすると、「count != 10」という条件式はすり抜けて、いつまでも条件式は偽になりません。 「count < 10」という条件式ならば、いつかは偽になるでしょうから、ループを抜け出すことができます。


練習問題

問題@ 標準入力から入力された整数分だけ、'*' を出力するプログラムを作成して下さい。

問題A 標準入力から5の倍数の整数を入力させるプログラムを作成して下さい。 5の倍数でない値が入力された場合、何度でも再入力を促すようにして下さい。

問題B 本文中のサンプルプログラム(標準入力から受け取った文字を 10回出力する)で、 while文の部分を、「今のところ何回ループしたか」という観点ではなく、 「あと何回ループさせるか」という観点で書き換えて下さい。


解答ページはこちら

参考リンク

更新履歴

'2009/3/27 新規作成。



前の章へ

次の章へ

C言語編のトップページへ

Programming Place Plus のトップページへ