whileとdo while
繰り返しの命令には、forの他にwhileと do whileがあります。これらはforのようなカウンタ変数を用いず、条件に従って処理を繰り返すだけの構造です。
whileの書式
先に、whileの書式を紹介しておきましょう。
while (<継続条件>) <処理>
<継続条件>に記述した式の評価が真である間、<処理>を繰り返し実行します。
forのようにカウンタ変数を増減する構造(再設定)の構造を持たないため、<処理>の中で<継続条件>に影響を与える(評価がいつか必ず偽になる)式を記述しておかなければ、永久に処理を繰り返す『無限ループ』となってしまいます。
forでは<初期設定>と<継続条件>を正しく記述すれば、必ず1回は<処理>が実行されますが、whileでは最初の段階で<継続条件>が偽であれば、<処理>を一度も実行しないままループを抜ける(whileの構造をとばしてその次の処理に移行する)場合があります。
九九プログラムを書き換える
whileを使った繰り返しの例として、先の九九プログラムを書き換えてみましょう。先のプログラムでは、元になる数を1回入力して計算結果が表示されれば処理が終わってしまいましたが、これを、続けて何度も入力できるようにしてみます。
ただ、それだけではプログラムが永久に終わらないので、「0」が入力されたらプログラムを終了することにします。ソースはリスト3のようになります ※1 。
リスト3の(a)の箇所でwhileを使い『変数numの値が0でない間』{ }内の処理を繰り返すようにしています。{ }内では、先のリスト2で紹介したforループで九九の計算と結果を表示しています。
リスト3では入力された値のチェックを行っていないため、数値以外の値(例えばアルファベットなど)を入力すると思わぬ動作をすることがあります。LSI-C 86でコンパイルしてWindows XPのコマンドプロンプトで動かしたところ、数値の代わりに'x'と入力したら処理を延々と繰り返す無限ループに陥りました(笑)。そのような場合には、[Ctrl]+[C]でプログラムを停止できます リスト3:whileを使って入力と計算を繰り返す九九プログラム(ex0803.c、ex0803.exe)
#include <stdio.h>
int main(void)
{
int i; /* forループ用のカウンタ変数 */
int num; /* ユーザーの入力した値を保持 */
printf("Input Base number : ");
scanf("%d", &num); /* 値を入力 */
/* 「0」が入力されるまで繰り返す */
while (num != 0) { -------- (a)
for (i=1; i<=9; i++) { /* 九九を計算して表示 */
printf("%d x %d = %d\n", num, i, num*i);
}
printf("Input Base number : ");
scanf("%d", &num); /* 次の値を入力 */
}
return (0);
}
do whileで書き直す
リスト3では、ユーザーに入力を求める以下の2行が、whileの前と繰り返し処理の中との2回登場します。
printf("Input Base number : ");
scanf("%d", &num);
これはちょっと冗長なので、もう少しシンプルにしてみましょう。それにはdo whileを用います。do whileの書式は以下のようになります。
do <処理>
while (<継続条件式>)
処理の後から判定
whileでは最初(ループに入る前)に継続条件が判定されましたが、do whileでは継続条件を判定する前に処理が必ず1回実行されます。
こうすることで、
まずユーザーからの入力を受け付ける
入力された値に基づいて九九の計算結果を表示する
という処理を繰り返す構造が作れます。
do whileを使えば、ソースはリスト4のようになります。しかし、これでは入力された値が1~9の場合でも、終了しようとして0を入力したときにも、九九の計算を行ってしまいます。終了させるつもりで0を入力した場合の実行結果は、画面2のようになります。正直に0×1、0×2……と計算をしているのですが、ちょっと無駄ですね。
そこで、ifを使って入力された値を調べ、それが1~9の範囲にあるときだけ九九の計算を行い、そうでないときには処理を抜け出してwhileの継続条件判定へ移行するようにしてみます。
すると、ソースコードはリスト5のようになります。実行結果は画面3で、0を入力すると九九の計算をしないでプログラム終了していることが分かります。このように、do whileは先に必ず処理を実行し、あとから継続条件を調べる構造となります。
リスト4:do whileを使って繰り返す九九プログラム(ex0804.c、ex0804.exe)
#include <stdio.h>
int main(void)
{
int i; /* forループ用のカウンタ変数 */
int num; /* ユーザーの入力した値を保持 */
do {
printf("Input Base number : ");
scanf("%d", &num); /* 値を入力 */
for (i=1; i<=9; i++) { /* 九九を計算して表示 */
printf("%d x %d = %d\n", num, i, num*i);
}
} while (num != 0); /* 「0」が入力されるまで繰り返す */
return (0);
}
リスト5:計算の前に入力された値をチェックする処理を付け加えた(ex0805.c、ex0805.exe)
#include <stdio.h>
int main(void)
{
int i; /* forループ用のカウンタ変数 */
int num; /* ユーザーの入力した値を保持 */
do {
printf("Input Base number : ");
scanf("%d", &num); /* 値を入力 */
/* numが1~9の間であるときだけ計算する */
if ((num >= 1) && (num <= 9)) {
for (i=1; i<=9; i++) { /* 九九を計算して表示 */
printf("%d x %d = %d\n", num, i, num*i);
}
}
} while (num != 0); /* 「0」が入力されるまで繰り返す */
return (0);
}
あとがき
hiropの『ちょっと気になる専門用語』~《ループ》
本文で紹介したように、繰り返し処理の構造を『ループ』と呼びます。ご存じの方は多いでしょう。
ループ(loop)を辞書で引けば「(糸・ひも・リボンなどで作った)輪」(研究社英和辞典より)などと説明されています。ただ、他にも輪を意味する語にはring、circleなどがあり、どれも日本語では「輪」と訳されるので「?」と感じる人もいると思います。
ringは指輪や腕輪などを意味するように、手に取れるサイズの小さな円形──といった意味が強く、circleは形としての輪──円・円周を意味します。loopは同じ輪でも正円である必要はなく、長いものの両端がつながって閉じた形態のものを指します。
そのためloopは『中が空洞になっている形状』や『ぐるぐると回って元に戻る形状』を意味することになるのです。
利害を同じにする人の集まりを意味するcircleは、複数の人が手をつないで輪を作ったイメージで、排他的なニュアンスも含まれます。一方、「同好会」といった意味で用いられる日本語の「サークル」には『和』に近いニュアンスがあります(「同好会」は英語ではclubです)。
米国の黒人霊歌から発した民謡に“Can the Circle Be Unbroken”という歌があります。家族や親子のつながりをテーマにした曲で、日本語では「永遠(とわ)の絆」と訳されています。これは、人が手と手をつなぐイメージですね(この曲のオリジナルはカーター・ファミリーの長男A.P.カーターが採譜してレコード化していますが、後に“Will the Circle Be Unbroken”というタイトルでNGDB──Nitty Gritty Dirt Bandがカバーしました)。
ringは『円』、circleは和語(漢字を充てない純粋な日本語)の『輪・和』、そしてloopは『環』という語が最も近いように思います。
和語の「わ」という音には実にいろいろな意味があります。漢字が入ってきてから同じ音に意味的に異なる文字が充てられたため、漢字にすると同じ『わ』でもそれぞれに異なる意味があると分かります。
これは、例えば色を表す『あか』に「赤・朱・緋」など微妙に異なる色を示す漢字が充てられているのと、根本の部分では同じです。古代の日本人は、色であれ状態や形状であれ、微妙な違いを認識していたにもかかわらず、それを同じ音の言葉で表していたんですね。
|