繰り返し文の使い方

繰り返し文の使い方


サイト全体の目次

稿


稿

同じ働きをする for 文と while 文

このセクションのソース

/*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*/ }

(untitled)

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*/ }

list-2.5.2-13

break文は for、while、do while 文の中で使うと「今いるループの1つ外へ抜けろ」という命令になります。「1つ」と書いたのは以前にも書いたように、これらの文が「ネスト」している場合、「いちばん外へ抜けるわけではない」からです。この例では無限ループから if 文で条件判断をし、break 文で抜けています。ここで注意してほしいのは、if 文は「break 文の対象ではない」という事です。つまり、この例では「if 文から抜ける」わけではなく、「while 文からぬける」のです。このことは、if 文がいくつネストしていても同じです。下の例を見てください。

while(1){	/*1*/
	while(1){	/*2*/
		if(1){	/* 無条件に実行される。*/
			if(1){
				break;
			}
		}
	}
}

ずいぶん深いネストになっていますが、こうするとどうなるのでしょう。if 文は break 文の対象ではありませんから、この break 文に達すると今いるループの1つ外へ抜けます。つまり /*2*/ のwhile 文を抜け、/*1*/ の while 文の処理を続行するわけです。

continue 文

このセクションのソース

場合によっては、「条件を満たせばそれ以下を実行せずに次のループを実行したい」という場合もあるでしょう。

/*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*/ }

list-2.5.3-16

continue文は for 文、while 文、 do while 文で使えます。この文は、ループ内で使われるとそれ以下の実行文を飛ばして、次の条件判断に移ります。ネストしている場合は continue 文が存在する深さのループが対象です。また、break 文同様 if 文は対象にならないので、if 文を使って処理を制御することも出来ます。この例では、割り算の計算で余りがある場合と、余りが無い場合とを分けて処理しています。余りが無いならば、それ用の printf 文を実行し、以下の実行文を実行せずに次のループに移ります。ちなみに、この例の場合は余りのケースを else 文でくくってしまっても同様の結果が得られます (*1) 。

このようにうまくプログラミングすれば continue 文は必要ありません。むしろ、この後で説明する goto 文と同様、処理の流れを強制的に変えてしまうため、あまり好ましい方法ではない、とする意見もあります。

goto 文

このセクションのソース

次は悪名高き「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-14

このgoto文はループ文に限らずどんなところでも使うことができ、指定されたラベル(「~:」の形)へ無条件で飛ぶという処理制御を行ないます。一見便利なようにも思えますが、プログラムというのは上から流れるように処理されていくのが普通なので、作法的には好ましいものではありません。goto 文を多用するとスパゲッティソースといってその流れがグチャグチャになり、大変分かりにくく、その結果エラーの多いものになってしまう可能性が出てくるのです。ですから、普通はほとんど使わないのですが利点もあります。

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*/ }

(untitled)

goto 文はさっきも書きましたが、どこにでも置くことができ、無条件で処理の流れを指定されたラベルへ飛ばします。そのため意味無く多用することは望ましくありません。

list-2.5.5 はラベルを多用した極端な例です。「start」から「end」まで 一本線な流れですが見にくいですね。また、飛ぶ先のラベルを 間違えると永久ループになりかねません。例えば「goto end;」の 行き先をどこか他のラベルへ変えてみてください。goto 文を使うときはくれぐれも慎重に行うようにしましょう。

練習問題

問題-2.5.1

問題-2.3.1 を while 文を使って書き直してください。

問題-2.5.2

問題-2.3.2 を while 文を使って書き直してください。

問題-2.5.3

list-2.5.3 を、break 文も contenue 文も使わない方法で作り直してください。

練習問題回答例

問題-2.5.1

#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;
}

問題-2.5.2

#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;
}

問題-2.5.3

#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;
}


読み込み中・・・
10秒待っても表示が変わらない場合、次の理由が考えられます。
・Javascript が無効になっています。
・検索エンジンのキャッシュを見ています。
サイトホームへ / 上位ページへ / ページトップへ / PAROFトレンドショッピングへ
Copyright (C) 2010 totobon all right reserved.