/*01*/ #include <stdio.h>
/*02*/
/*03*/ main()
/*04*/ {
/*05*/ int i;
/*06*/
/*07*/ /*** for 文 パターン ***/
/*08*/ printf("for 文です。\n");
/*09*/ for(i = 0; i < 5; i++){
/*10*/ printf("%d 回目のループです。\n", i);
/*11*/ }
/*12*/
/*13*/ /*** while 文 パターン***/
/*14*/ printf("while 文です。\n");
/*15*/ i = 0;
/*16*/ while(i < 5){
/*17*/ printf("%d 回目のループです。\n", i);
/*18*/ i++;
/*19*/ }
/*20*/
/*21*/ return 0;
/*22*/ }
list-2.5.1 では二通りのループ処理を行っていますが、処理の流れはほぼ一緒であることが分かると思います。for 文、while 文は、実行文中に条件判断用の変数値を変える文や break 文、下に述べる continue 文を入れることでより有効的な使い方が出来ます。しかし、上に書いたとおり、 for 文と while 文は条件判断用の変数値さえ気をつければまったく同じ機能であることがわかります。for 文は while 文の特殊な場合と考えることも出来るでしょう。そのため、while 文のほうが融通が利くので、この章ではこれ以降 while 文を使って解説します。
/*01*/ #include <stdio.h>
/*02*/
/*03*/ main()
/*04*/ {
/*05*/ int x;
/*06*/
/*07*/ printf("0 を入力すると終了です。\n");
/*08*/
/*09*/ while(1){
/*10*/ printf("整数を入力してください。-> ");
/*11*/ scanf("%d", &x);
/*12*/ if(x == 0){
/*13*/ break;
/*14*/ }
/*15*/ printf(" %d の自乗は %d です。\n", x, x*x);
/*16*/ }
/*17*/
/*18*/ return 0;
/*19*/ }
while(1){ /*1*/
while(1){ /*2*/
if(1){ /* 無条件に実行される。*/
if(1){
break;
}
}
}
}
場合によっては、「条件を満たせばそれ以下を実行せずに次のループを実行したい」という場合もあるでしょう。
/*01*/ #include <stdio.h>
/*02*/
/*03*/ main()
/*04*/ {
/*05*/ int x, y;
/*06*/
/*07*/ printf("最初の数に 0 を入力すると終了です。\n");
/*08*/ while(1){
/*09*/ printf("整数を2つ入力してください。-> ");
/*10*/ scanf("%d%d", &x, &y);
/*11*/ if(x == 0){
/*12*/ break;
/*13*/ }
/*14*/ if(x % y == 0){
/*15*/ printf(" %d / %d は %d です。\n", x, y, x/y);
/*16*/ continue;
/*17*/ }
/*18*/ printf(" %d / %d は %d 余り %d です。\n", x, y, x/y, x%y);
/*19*/ }
/*20*/
/*21*/ return 0;
/*22*/ }
次は悪名高き「goto」文です。
/*01*/ #include <stdio.h>
/*02*/
/*03*/ main()
/*04*/ {
/*05*/ int x;
/*06*/
/*07*/ while(1){
/*08*/ while(1){
/*09*/ while(1){
/*10*/ printf("0 で終了です。\n");
/*11*/ printf("整数を入力してください。-> ");
/*12*/ scanf("%d", &x);
/*13*/ if(x == 0){
/*14*/ goto end;
/*15*/ }
/*16*/ printf("入力された数は %d です。\n");
/*17*/ }
/*18*/ }
/*19*/ }
/*20*/ end:
/*21*/ return 0;
/*22*/ }
この
list-2.5.4 のように深いネストになっている場合、最深部で条件判断し break 文を使っても、1つ上のループに抜けるだけです。ですから、いちばん外へ抜けるためには、すべてのループから抜けるために何度も条件判断する文が必要になってきます。この例なら同じ条件判断を全部で3回しないといけないわけです。しかし、それでは同じ文を何度も書くことになりますし、ソース自体見にくくなってしまいます。そこで break 文の代わりに goto 文を使います。ネストしているループの最も外へラベルを書いておき、そこへ処理の流れを飛ばすことで一気にネストしているすべてのループから抜けることができるのです。書式は見てのとおり「goto ラベル;」と「ラベル:」で、ラベルにはどんな名前をつけてもかまいません。それから、注意して欲しいのは「goto ラベル;」の終わりが「;」なのに対して「ラベル:」の方は「:」であるという点です。
/*01*/ #include <stdio.h>
/*02*/
/*03*/ main()
/*04*/ {
/*05*/ goto start;
/*06*/ nagoya:
/*07*/ goto osaka;
/*08*/ kawasaki:
/*09*/ goto tokyo;
/*10*/ nigata:
/*11*/ goto end;
/*12*/ start:
/*13*/ goto yokohama;
/*14*/ tokyo:
/*15*/ goto nagoya;
/*16*/ osaka:
/*17*/ goto hukuoka;
/*18*/ sapporo:
/*19*/ goto nigata;
/*20*/ yokohama:
/*21*/ goto kawasaki;
/*22*/ hukuoka:
/*23*/ goto sapporo;
/*24*/ end: printf("終了します。\n");
/*25*/ return 0;
/*26*/ }
goto 文はさっきも書きましたが、どこにでも置くことができ、無条件で処理の流れを指定されたラベルへ飛ばします。そのため意味無く多用することは望ましくありません。
list-2.5.5 はラベルを多用した極端な例です。「start」から「end」まで 一本線な流れですが見にくいですね。また、飛ぶ先のラベルを 間違えると永久ループになりかねません。例えば「goto end;」の 行き先をどこか他のラベルへ変えてみてください。goto 文を使うときはくれぐれも慎重に行うようにしましょう。
問題-2.3.1 を while 文を使って書き直してください。
問題-2.3.2 を while 文を使って書き直してください。
list-2.5.3 を、break 文も contenue 文も使わない方法で作り直してください。
#include <stdio.h>
main()
{
int i, x, wa = 0;
printf("整数値を入力して下さい。 -> ");
scanf("%d", &x);
i = 1;
while(i <= x){
wa += i;
i++;
}
printf("1~%d までの和 -> %d\n", x, wa);
return 0;
}
#include <stdio.h>
main()
{
int i, j;
i = 1;
while(i <= 9){
j = 1;
while(j <= 9){
printf("%2d ", i * j);
j++;
}
printf("\n");
i++;
}
return 0;
}
#include <stdio.h>
main()
{
int x, y;
printf("最初の数に 0 を入力すると終了です。\n");
x = 1; /* まず x を非ゼロとして一回目のループを確実に行えるようにする。 */
while(x != 0){
printf("整数を2つ入力してください。-> ");
scanf("%d%d", &x, &y);
/* もし、x がゼロなら、何もせずに次の while 条件判断に行き、
そこでループから抜ける。 */
if(x != 0){
if(x % y == 0){
printf(" %d / %d は %d です。\n", x, y, x/y);
/* 今回の場合、else を使うことで contenue を使わなくてすむ。 */
}else{
printf(" %d / %d は %d 余り %d です。\n", x, y, x/y, x%y);
}
}
}
return 0;
}
#include <stdio.h>
main()
{
int x, y;
printf("最初の数に 0 を入力すると終了です。\n");
/* x = 1 とする代わりに、do ループを使って確実に一回目の入力を行う */
do{
printf("整数を2つ入力してください。-> ");
scanf("%d%d", &x, &y);
if(x != 0){
if(x % y == 0){
printf(" %d / %d は %d です。\n", x, y, x/y);
}else{
printf(" %d / %d は %d 余り %d です。\n", x, y, x/y, x%y);
}
}
}while(x != 0);
return 0;
}
#include <stdio.h>
main()
{
int x, y;
printf("最初の数に 0 を入力すると終了です。\n");
/* 最初の入力をループ前に行ってしまうことで、x != 0 の判定が
一回だけ(while 文だけ、if 文なし)ですむ。 */
printf("整数を2つ入力してください。-> ");
scanf("%d%d", &x, &y);
while(x != 0){
if(x % y == 0){
printf(" %d / %d は %d です。\n", x, y, x/y);
}else{
printf(" %d / %d は %d 余り %d です。\n", x, y, x/y, x%y);
}
/* 処理の順序を考えると、次の入力はこの位置。 */
printf("整数を2つ入力してください。-> ");
scanf("%d%d", &x, &y);
}
return 0;
}