第4週 do while文を用いたプログラムの流れの繰り返し
INDEX

目標

  • while文を使って、繰り返し処理を実現することができる。
  • while文とdo〜while文を区別して利用することができる。

予習・復習

 以下のスライドを利用して、予習と復習をしよう。復習では、自分の理解度を確認するために、実際にプログラムを作成し、意図する結果が得られるか確認しよう。
  1. do while文

本日の講義・演習予定

  1. do〜while文
  2. continu文とbreak文
  3. while文
  4. 演習問題
  5. 提出課題
内 容
  1. do〜while文
  2. continu文とbreak文
  3. while文

do〜while文

do〜while文

 do〜while文は与えられた処理を何度も繰り返すための構文です。繰り返したい処理は、doの後のコードブロック{ }の中に記述します。繰り返し処理を継続するか否かはwhileの直後の括弧の中に記述する条件式によって決まります。条件式が真(true)ならばコードブロック{}の先頭に再び戻って処理を継続します。もし、偽(false)ならばdo〜while文を終了します。
 次のプログラム例は、整数値を入力してその値が非負の整数ならば繰り返し処理を継続し、負の整数ならば繰り返し処理を終了します。
例 dowhile.c
#include <stdio.h>

int main(void)
{
	int n;

	do {
		printf("非負の整数>> ");
		scanf("%d", &n);
		if (n<0){
			printf("非負の整数ではありません。もう一度入力し直してください。\n");
		}
	} while (n<0);

	return 0;
}

構文:
do {

    繰り返す処理

} while (条件式)
流れ図:
do while
繰り返しの判定条件が処理の後ろにあるので、必ず1度は処理が行われる。

カウントアップ、カウントダウン

 while文を使って、1から10までカウントアップしながら整数を表示するプログラムです。
例 countup10.c
#include <stdio.h>

int main(void)
{
	int i = 1;

	do {
		printf("%d\n", i);
		i = i + 1;		// カウントアップ
	} while (i<=10);		// iの値が11になったら終了する

	return 0;
}

 次は、10から1までカウントダウンしながら整数を表示するプログラムです。
例 countdown10.c
#include <stdio.h>

int main(void)
{
	int i = 10;

	do {
		printf("%d\n",i);
		i = i - 1;		// カウントダウン
	} while (i>0);		// iの値が−1になったら終了する

	return 0;
}

繰り返しの判定、プログラムは必ず終了しなければならない

 次のプログラムは、整数を入力して偶数か奇数かを繰り返し判定することができるプログラムです。繰り返し処理do〜whileを継続するか否かを判定するために、ここではy(yes)/n(no)のいずれかの文字の入力を求めて、'y'が入力された場合にのみ継続することにしました。
例 yesno.c
#include <stdio.h>

int main(void)
{
	int n;
	char ch;

	do {
		printf("整数>> ");
		scanf("%d", &n);

		if(n%2)
			puts("奇数です。\n");
		else
			puts("偶数です。\n");
		
		printf("続けて入力する?[y/n]>> ");
		scanf("%*c%c", &ch);		// %*cで前のscanfで読み込んだ改行文字を読み捨てる
	} while (ch=='y');
	
	return 0;
}
プログラムは必ず終了しなければならい。

文字を読み込むためのscanfの連続使用時の注意点
 scanfを使ってキーボードから入力する際、その入力を確定するためには必ず最後にenterキーを入力します。例えば、文字yを入力すためには、[y] [enter]と入力します。この時、入力バッファには文字'y'に加えて改行文字'\n'が入力されます。つまり1文字入力するために2文字が入力されているわけです。しかし、scanf("%c", &c)は1文字'y'だけしか読み込んではくれません。入力バッファには改行文字'\n'が残ることになります。そのため、次のscanf("%c", &c)は、入力バッファに残った改行文字'\n'を読み込んでしまい、次に入力する文字を正しく読み込んではくれないのです。
 では、どうしたら良いのでしょう。とにかく不要な改行文字'\n'を読み捨てれば良いので、いくつかの方法が考えられます。上記のプログラム例では、scanf("%*c%c", &ch);として、その前のscanfで入力された改行文字'\n’を「読み込むが代入はしない」という変換指定子%*cを使って読み捨てるようにします。

1からNまでの合計値を求める

 1からNまでの合計値を求める方法を考えてみます。
1〜2までの合計値は、1+2
1〜3までの合計値は、1+2+3
1〜4までの合計値は、1+2+3+4
1〜5までの合計値は、1+2+3+4+5
・・・
1〜Nまでの合計値は、1+2+3+・・+i+・・+(N-1)+N
となります。
 同様の計算をプログラムとして表現するために、これを「手順」に置き換えてみます。
手順1:合計値を格納する変数sumを用意して0で初期化する。
手順2:合計値に加算する値を格納する変数iの値を1にする。
手順3:変数sumに変数iの値を加算した結果を変数sumに代入する。
手順4:変数iの値をインクリメントする。
手順5:変数iの値がN以下である間、手順3〜4を繰り返す。

 これをプログラムにしたものが次の例sumof.cです。
例 sumof.c
#include <stdio.h>

int main(void)
{
	int sum=0, i=1,n;		//合計

	printf("整数>> ");
	scanf("%d", &n);

	do {
		sum = sum + i;
		i = i + 1;
	} while (i<=n);

	printf("1から%dまでの合計は、%dです。\n", n,sum);

	return 0;
}
0からNまでの合計を求めるためには、
0で初期化した変数sumに、1〜Nまでの値を順番に加算していく。

cotinue文とbreak文

 正の整数を入力して、その平方根を求めるプログラムを考えます。 

continue文

 C言語には平方根を求めるための関数sqrt()が用意されています。この関数を利用するためにヘッダファイルmath.hでをインクルードします。次に、sqrtは負の値に対する解を求めることができないので、正の整数だけを受け付けるようにします。入力部分にdo while文を使って正の数が入力されるまで処理を繰り返すという方法もありますが、ここではcontinue文を使って実現しています。continue文は、ブロック内のそれ以降の処理をキャンセルする命令です。この例では、負数が入力された場合には、直後のprintf文を処理せず、ブロックの先頭に戻ることになります。
whileCotinue.c
#include <stdio.h>
#include <math.h>

int main(void)
{
	int a;

	do {
		printf("正の整数(99入力で終了)>> ");
		scanf("%d", &a);
		if(a<=0) continue;		//真ならばブロック内の以降の処理を行わない

		printf("%.3f\n",sqrt(a));		//sqrtの引数、戻り値ともdouble型
	} while(a!=99);
	return 0;
}

無限ループとbreak文

 次の例も、上記と同様に関数sqrt()を使って、平方根の値を求めるプログラムです。ただし、繰り返し入力を実現するためにdo while文の条件式を1、すなわち「真(true)」として無限ループを構成しています。もちろん、それだけではいつまでたっても終了することができないため、99が入力された時にだけブロック内から脱出するための命令break文を設定します。
whileBreak.c
#include <stdio.h>
#include <math.h>

int main(void)
{
	int a;

	do {
		printf("正の整数(99入力で終了)>> ");
		scanf("%d", &a);
		if(a == 99) break;		//ブロックを脱出する
		if(a<=0) continue;		//真ならば以降の処理を行わない

		printf("%.3f\n",sqrt(a));		//sqrtの引数、戻り値ともdouble型
	} while(1);
	return 0;
}

while文

繰り返し画面に表示する

 while文もdo〜while文と同様に繰り返し処理をするための構文です。この二つの構文の大きな違いは、do〜while文の繰り返しの判定条件が処理の後にあるのに対してwhile文が処理の前にある点です。do〜while文が繰り返し条件の真偽にかかわらず波括弧{}の中を少なくとも1回は処理するのに対して、while文は条件によっては一度も処理をしない可能性があります。
画面にメッセージを10回繰り返して表示するプログラム例c6-3.cです。int型の変数iは、繰り返しの回数を数えあげるためのカウンタ変数です。値0で初期化されているので、
例 whileLoop.c
#include <stdio.h>

int main(void)
{
	int i=0;
	
	while(i<10){
		printf("I love C programing.¥n");
		i++;			//カウントアップ
	}

	return 0;
}

構文:
while(条件式) {

    繰り返す処理

}
流れ図:
while
条件によっては一度も処理されないことがある。


expand_lessBack to TOP

演習問題

  1. 次は、画面に「羊が1匹、羊が2匹、・・・」と100匹まで数えるプログラムです。空欄を埋めて完成させなさい。
  2. ex4-1.c
    #include <stdio.h>
    
    int main(void)
    {
    	int i=1;
    	
    	do {
    		printf("羊が%d匹\n", i);
    		i = [[空欄ア]];
    	} while([[空欄イ]]);
    	printf("Zzz、Zzz、Zzzzz、....\n");
    
    	return 0;
    }
    
  3. 次は、1から99までカウントアップしながら数字を表示するプログラムです。空欄を埋めて完成させなさい。
  4. ex4-2.c
    #include <stdio.h>
    
    int main(void)
    {
    	int i = [[空欄ア]];
    
    	do {
    		i = [[空欄イ]];	// カウントアップ
    		printf("%d\n", i);
    	} while ([[空欄ウ]]);
    
    	return 0;
    }
    

  5.  乱数使った数当てゲームです。当たり数に近づくために、入力した値より大きければ「大きい」、小さければ「小さい」と表示するようにします。当たりが出たら「あたり!」と表示します。空欄を埋めてプログラムを完成させなさい。
  6. ex4-3.c
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    
    int main(void)
    {
    	int n, hit;
    	
    	srand((unsigned int)time(NULL));	//乱数に種を植える
    	hit = rand()%[[空欄ア]] + 1;		//1〜99の乱数を生成
    	
    	printf("== 数当てゲーム ==¥n");	
    	do{
    		printf("整数>> ");	
    		scanf("%d", &n);
    
    		if(n>hit){
    			printf("大きい。¥n");		
    		}
    		else if([[空欄イ]]){
    			printf("小さい。¥n");
    		}
    	} while([[空欄ウ]]);
    	printf("あたり!¥n");
    	
    	return 0;
    }
    

  7. 前問と同じ数当てゲームをwhile文を使って実現したプログラムex4-4.cを作成しなさい。

  8. 数当てゲームに、当たり数との差が10未満の場合は「少し小さい」もしくは「少し大きい」と表示し、50以上の場合は「かなり大きい」もしくは「かなり小さい」と表示するように追加したプログラムex4-5.cを作成しなさい。

  9. 回答できる回数を7回までに制限した数当てゲームプログラムex4-6.cを作成しなさい。もし、7回目までに当てることができなかった場合は、「残念でした」と表示すること。

  10. 1から100までの整数で、3の倍数ならば「Fizz」、5の倍数ならば「Buzz」、15の倍数ならば「Fizz Buzz」と表示するプログラムex4-7.cをwhile文を使って作成しなさい。

  11. 年利0.1%で、毎年5,000円積み立てて、10万円貯めるためには何年かかるかを求めるプログラムex4-9.cを作成しなさい。

  12. コンピュータと対戦するじゃんけんゲーム・プログラムを作成しなさい。3回勝負として、コンピュータの手は乱数で決めるものとします。

  13. 次は、数列\(x_{n+1} = 0.5x_n + 3\) において、\(n→∞\)の時どのような値に収束するかを求めるプログラムです。実行した結果が正しいか、解析的に求めた結果と比較しなさい。
  14. ex4-11.c
    #include <stdio.h>
    
    int main(void)
    {
    	double x1,x2;
    
    	x2 = 1.0;
    
    	do{
    		x1 = x2;
    		x2 = 0.5 * x1 + 3.0;
    		printf("%f\n", x2);
    	}while( x1-x2 > 0.000001 || x2-x1 > 0.000001);
    
    	return 0;
    }
    


演習問題解答

OPEN ANSWER
  1. ア. i+1 イ. i<=100

  2. ア. 0 イ. i = i + 1 ウ. i <=98 もしくは i<99

  3. ア. 99 イ. n<hit ウ. n != hit

  4. 回答例
  5. code/4/ex4-4.c

  6. 回答例
  7. code/4/ex4-5.c

     回答例2
    code/4/ex4-5s.c

  8. 回答例
  9. code/4/ex4-6.c

  10. 回答例
  11. code/4/ex4-7.c

  12. 回答例
  13. code/4/ex4-9.c

  14. 回答例
  15. code/4/ex4-10.c

expand_lessBack to TOP

確認テスト1

確認テスト2
初項a、公差dの等差数列の第n項を求めるプログラムap1.cを作成しなさい。ただし、a=1、d=2として、nの値はキーボードから入力できるものとする。
確認テスト3
初項a、公差dの等差数列の項数nの時の和を求めるプログラムap2.cを作成しなさい。ただし、a=1、d=2として、nの値はキーボードから入力できるものとする。

本日の提出課題

以下の各プログラムを作成しなさい。ただし、do-while文もしくはwhile文を利用して実現すること。
  • 課題1
  • 整数を入力して桁数を求めるプログラム。

  • 課題2
  • 1からnまでの整数の合計が100以上になるためのnの最小値を求めるプログラム。break文を使わず実現すること。

  • 課題3
  • 初項$a_0=2$、公比$d=3$の等比数列の項数nを入力して、その和を求めるプログラム

  • 課題4
  • 整数を入力して全ての桁が奇数かそうでないかを判定するプログラム

  • 課題5
  • 3以上の整数nを入力して、漸化式$a_n=a_{n-1}+a_{n-2}$ 、$a_1=1$, $a_2=1$で表されるフィボナッチ数列の第n項までを求めるプログラム

 初項\(a\)、項比\(r\)からなる等比数列の初項から第n項\(ar^{n-1}\)までの和\(S_n (= \sum_{k=1}^n ar^{k-1}) = ar^0 + ar^1 + ar^2 + \dots ar^{n-1}\)を求める下記に示すプログラムkadai4.cを完成させなさい。ただし、項比は\(0\gt r \gt1\)の範囲にあり、\(n \to \infty\)のとき\(S_n\)は一定の値に収束するものとします。ここでは、\(a=1, r=0.9\)として\(S_n\)と\(S_{n-1}\)との差が\(\epsilon = 0.00001\)より小さくなった場合に一定値になったものとしてます。
[プログラム]
#include <stdio.h>
		
int main(void)
{
	double a = 1.0, r = 0.9;			//初項、公比
	double sum = 0.0, sum_old;	//合計、一つ前の合計
	double term;							//第k項
	double eps = 0.00001;			//誤差

	;					//初項(k=1)の決定
	;					//k=1までの合計の決定

	do{
		;				// 一つ前の合計の決定
		;       		//第k項の決定
		;				//合計を求める
	}while(  ...繰り返し条件... );		//誤差よりも小さくなったら繰り返し処理を終了

	printf("初項%.1f 項比%.1f の等比数列の和は%f\n", a, r, sum);

	return 0;
}
		

  • [提出方法]
    1. ideone.comを利用して作成した課題プログラムのURLをCoursePowerへ提出のこと。
    2. 適切な実行結果を含むこと
    3. 詳細はスライド「ideoneの使い方」参照のこと。

  • [評価について]
  • プログラムの内容の評価とは別にideone.com上で以下の要件を満たすことを評価の前提とする。
    1. C言語で記述されていること。
    2. ソースコードファイルのコンパイル結果に、ワーニングやエラーが出力されていないこと。
    3. 所定の実行結果が得られるていること。
    4. ソースコードは、インデントや適当な改行が施された見やすい状態であること。

  • [提出期限]
  • 2023年 5月15日(月)までとする。ただし、以降の提出も受け付ける。