前回の練習問題の解答例

#include <stdio.h>
#include <math.h>

int main(void)
{
	int counter, num;
	double length1, length2, length3, temp, area;
	
	printf("三角形の個数:");
	scanf("%d",&num);
	
	area=0.0;
	for (counter=1; counter<=num; counter++) {
		printf("%d個目の三角形の3辺の長さ:",counter);
		scanf("%lf%lf%lf",&length1,&length2,&length3);
		temp=(length1+length2+length3)/2.0;
		area=area+sqrt(temp*(temp-length1)*(temp-length2)*(temp-length3));
	}
	printf("三角形の面積の合計は%fです。\n",area);
	return 0;
}
以前作ったヘロンの公式のプログラムを流用すればよい。
3辺の長さを入力してから面積を求めるまでを、for文の波括弧{ }の中に入れる。 繰り返し条件を書けば、三角形の面積が繰り返し計算されることになる。 scanf関数で整数型変数numに三角形の個数を代入し、これを用いて繰り返し条件を書けばよい。 繰り返し条件は「counter=1; counter<=num; counter++」となる。
「area=area+sqrt(...)」は、右辺で1つ前までの三角形の面積の合計「area」を参照し、それに今回の三角形の面積「sqrt(...)」を加えることで、今回までの三角形の面積の合計を求めており、それを左辺の変数areaに代入している。 しかし、ループ1回目の右辺のareaにはまだ何の数値も代入されておらず、このままでは代入文より前に変数areaを参照してしまう。 そこで、for文の前に「area=0.0」という代入文が必要となる。

while文

今回はwhile文の使い方を学ぶ。

while文の書き方


書き方:
	while (条件) {
		処理;
	}


処理の順番:

for文からwhile文への書き換え1

「hello, world」と10回表示するプログラム:
#include <stdio.h>

int main(void)
{
	int counter;
		
	counter=1;
	while (counter<=10) {
		printf("hello, world\n");
		counter++;
	}
	return 0;
}
for文と違ってwhile文には初期化式と増減式がないが、この例ではfor文の初期化式に相当する「counter=1」と増減式に相当する「counter++」を書いており、実質的には前回for文を使って書いたプログラムと同じである。

for文からwhile文への書き換え2

n回目のループで「n回目」と表示するプログラム:
#include <stdio.h>

int main(void)
{
	int counter;
		
	counter=1;
	while (counter<=10) {
		printf("%d回目\n",counter);
		counter++;
	}
	return 0;
}


for文からwhile文への書き換え3

数列「-2 1 4 7 10 13 16 19 22 25」を表示するプログラム:
#include <stdio.h>

int main(void)
{
	int counter;
		
	counter=-2;
	while (counter<=25) {
		printf("%d ",counter);
		counter=counter+3;
	}
	printf("\n");
	return 0;
}
以上のように、for文で書いたプログラムは必ずwhile文に書き換えることができる。

ここまでのまとめ: for文とwhile文の比較


							初期化式;
	for (初期化式; 条件; 増減式) {			while (条件) {
		処理;						処理;
	}							増減式;
							}


繰り返し回数が決まっていない繰り返し処理1

キーボードから入力された商品価格を合計するプログラムを作る。 予算は1000円とする。 すなわち、合計が1000円を超えた時点でループを終了し、最後の商品を除いた合計金額を表示する。
#include <stdio.h>

int main(void)
{
	int price, sum;
		
	printf("1000円で買い物をします。\n");
	sum=0;
	while (sum<=1000) {
		printf("現在の合計は%d円です。商品価格:",sum);
		scanf("%d",&price);
		sum=sum+price;
	}
	printf("1000円を超えたので、最後の商品は購入できません。\n");
	printf("1つ前の商品までの合計は%d円です。\n",sum-price);
	return 0;
}
このwhile文はループカウンターを使っていない。

繰り返し回数が決まっていない繰り返し処理2

キーボードから入力された商品価格を合計するプログラムを作る。 キーボードから0が入力された時点でループを終了するものとする。
#include <stdio.h>

int main(void)
{
	int price, sum;
		
	price=1;		//0以外の値を代入する(1でなくてもよい)
	sum=0;
	while (price!=0) {
		printf("現在の合計は%d円です。商品価格(0で終了):",sum);
		scanf("%d",&price);
		sum=sum+price;
	}
	printf("合計は%d円です。\n",sum);
	return 0;
}


無限ループとbreak文

while (1) のように、while文の条件を論理式ではなく 1 にすると無限ループになる。 しかし、本当に無限に続くと困るので、break文でループを中断する方法をとる。 break文は繰り返し処理を中断する文である。 for文やwhile文の波括弧{ }の中でbreak文が実行されると、その時点で繰り返し処理が終了する。

条件分岐の回に、キーボードから点数を入力して 0〜59点なら「不合格」、60〜100点なら「合格」と表示し、それ以外なら何も表示しないプログラムを作った。 これを書き換えて、0〜100の範囲から外れる数値が入力されたら、0〜100の数値が入力されるまで何度でも入力を求めるようにしてみる。
#include <stdio.h>

int main(void)
{
	int score;
		
	printf("点数:");
	while (1) {
		scanf("%d",&score);
		if (score>=0 && score<=100) {
			break;
		}
		printf("0〜100の点数:");
	}
		
	if (score>=0 && score<=59) {
		printf("不合格\n");
	} else if (score>=60 && score<=100) {
		printf("合格\n");
	}
	return 0;
}
scanf関数で0未満あるいは100超の数値を入力すると、次のif文の条件が偽となるので波括弧{ }は飛ばされて「0〜100の点数:」と表示され、whileの丸括弧( )に戻る。無限ループなので、0未満か100超の数値が入力され続ける限り何度でもこれを繰り返す。
scanf関数で0以上100以下の数値を入力すると、次のif文の条件が真となるので波括弧{ }内のbreak文が実行され、そこで繰り返し処理が終了となる。「0〜100の点数:」は表示されない。

continue文

break文と似たcontinue文というものがある。 continue文は、繰り返し処理のその回だけを打ち切る文である。 繰り返し処理自体は継続する。

先程の無限ループのプログラムを、continue文を使う形に書き換えてみる。
#include <stdio.h>

int main(void)
{
	int score;
		
	printf("点数:");
	while (1) {
		scanf("%d",&score);
		if (score<0 || score>100) {
			printf("0〜100の点数:");
			continue;
		}
		break;
	}
		
	if (score>=0 && score<=59) {
		printf("不合格\n");
	} else if (score>=60 && score<=100) {
		printf("合格\n");
	}
	return 0;
}
scanf関数で0未満あるいは100超の数値を入力すると、次のif文の条件が真となるので波括弧{ }が実行されて「0〜100の点数:」と表示され、continue文によりwhileの丸括弧( )に戻る。無限ループなので、0未満か100超の数値が入力され続ける限り何度でもこれを繰り返す。
scanf関数で0以上100以下の数値を入力すると、次のif文の条件が偽となるので波括弧{ }が飛ばされてbreak文に進み、そこで繰り返し処理が終了となる。

フラグ

フラグ(flag)とは 真か偽の値を持つ変数のことであり、条件分岐や繰り返し処理の条件として論理式の代わりに使う。 C言語では整数型変数をフラグとして使うことが多い。 その場合、0が偽、それ以外の値が真を意味する。 フラグを真にすることを「フラグを立てる」、偽にすることを「フラグを倒す」と言う。

先程の無限ループのプログラムを、フラグを使う形に書き換えてみる。
#include <stdio.h>

int main(void)
{
	int score, flag;
		
	flag=1;
	printf("点数:");
	while (flag) {
		scanf("%d",&score);
		if (score>=0 && score<=100) {
			flag=0;
		} else {
			printf("0〜100の点数:");
		}
	}
		
	if (score>=0 && score<=59) {
		printf("不合格\n");
	} else if (score>=60 && score<=100) {
		printf("合格\n");
	}
	return 0;
}
while文の前の「flag=1」でフラグを立てている。 while文の丸括弧( )の中には論理式の代わりにflagと書かれており、変数flagの値が0以外なら真と見なされるので、フラグを立てておくと繰り返し処理の初回は必ず実行される。 while文の波括弧{ }の中では、scanf関数で0以上100以下の数値を入力した場合は「flag=0」でフラグを倒し、それ以外の場合はflagを変更していない。 つまり、scanf関数で0以上100以下の数値を入力しない限りフラグが立ったままなので繰り返し処理は継続するが、0以上100以下の数値を入力するとフラグが倒れ、whileの丸括弧( )に戻った時点で繰り返し処理が終了することになる。

上に戻って「繰り返し回数が決まっていない繰り返し処理2」のプログラムを見てほしい。 「while (price!=0)」と書いているので、商品価格の変数priceに0を代入すると、whileの丸括弧( )に戻った時点で繰り返し処理が終了する。 「0なら終了」という動作はフラグと同じなので、実はpriceは商品価格であると同時にフラグとしても使うことができる。 つまり「while (price)」と書くこともできるのである。
#include <stdio.h>

int main(void)
{
	int price, sum;
		
	price=1;		//0以外の値を代入する(フラグを立てる)
	sum=0;
	while (price) {		//変数priceをフラグとして使っている
		printf("現在の合計は%d円です。商品価格(0で終了):",sum);
		scanf("%d",&price);
		sum=sum+price;
	}
	printf("合計は%d円です。\n",sum);
	return 0;
}


練習問題

1ヶ月目は1円を貯金、2ヶ月目は2円を貯金、3ヶ月目は4円を貯金、…、nヶ月目は2n-1円を貯金という、いわゆる倍々貯金を考える。
残高が100万円以下の時は「○ヶ月目は○円を入金、残高○円」と表示し、 残高が100万円を超えたら「○ヶ月目は○円を入金、残高○円で100万円を超えました。」と表示して終了するプログラムを作りなさい。