繰り返し処理

アルゴリズムと繰り返し処理

コンピュータのプログラムの処理には、順次処理(じゅんじしょり)分岐処理(ぶんきしょり)があることはすでに述べました。ここでは、もうひとつの処理、繰り返し処理について説明します。 コンピュータのプログラムのプログラムの処理のことを、一般にアルゴリズムと言いますが、アルゴリズムは、この3つの処理によって記述されています。ここでは、C言語における繰り返し処理の記述方法について説明します。

for文

サンプルプログラム

では、まず手始めに繰り返し処理の最も基本的な処理である、for(フォー)文について学んでいくことにしましょう。for文は、{}で囲まれた処理を、指定した条件が満たされるまで繰り返す処理です。 繰り返し処理をループ処理ということから、for()文による繰り返しを、forループとも呼びます。forループは、C言語のプログラムの中で最もよく使われる処理の一つです。しっかりと覚えておきましょう。

まずは、以下のサンプルを実行してみてください。

list4-1:main.c
#include <stdio.h>

void main(){
   int i;
   for(i = 1;i <= 5;i++){
	   printf("%d ",i);
   }
   printf("¥n");
}
実行結果
1 2 3 4 5

for文の書式

プログラムの結果をみると、for()文の{}に囲まれた部分が5回実行されたことが分かります。しかも、iが、1から5に1つづつ増加していたことはわかります。 ではなぜこのような結果になるのでしょう。それを知る前に、まずはfor文の書式をみてみましょう。

for文の書式
for ( 初期化処理 ; 条件式 ; 増分処理 ){
    処理
}

list4-1にあてはめてみると、初期化処理の部分で、まず、「i = 1」としていますから、まず、最初はiの値は1から始まるわけです。条件式は、if文で用いられるものと同じもので、この場合「i <= 5」ですから、iが5以下の場合、この処理は継続されるわけです。 では、増分処理には「i++」と書いてありますが、これは一体なんでしょうか?これは、インクリメントと言って、iの値を1増加させる処理なのです。

以上より、このfor文は、i=1から始めて、iを一つずつ増分させていき、iが5以下ならば{}内の処理を実行することを繰り返し、iが5より大きくなれば、ループから抜ける という処理になるのです。(図4-1)

図4-1.forループの仕組み
C言語のforループの仕組み

インクリメント・デクリメント

for文では、このインクリメントおよび、デクリメントという処理をよく行います。デクリメントとは、インクリメントの反対で、変数の値を1減らす処理です。この処理を表にまとめると、以下のようになります。(表4-1)

表4-1:インクリメント・デクリメントの処理一覧
演算子 呼び名 意味 該当する演算
i++ インクリメント(後置:こうち) 変数の値を1増加させる。 i=i+1;
i+=1;
++i インクリメント(前置:ぜんち) 変数の値を1増加させる。
i-- デクリメント(後置:こうち) 変数の値を1減少させる。 i=i-1;
i-=1;
--i デクリメント(前置:ぜんち) 変数の値を1減少させる。

前置と後置

これをみると、i++と++i、i--と--iはそれぞれまったく同じ意味であるように見えます。しかし、このように前置(ぜんち)後置(こうち)があるのには、それぞれ意味があるのです。例えば、

int a1=1,b1=1,c1=1,d1=1;
int a2,b2,c2,d2;
a2=a1++;
b2=++b1;
c2=c1--;
d2=--d1;

といった処理を行うと、a1~d1,a2~d2はそれぞれ、以下のような値になるのです。

a1 = 2  b1 = 2  c1 = 0  d1 = 0  a2 = 1  b2 = 2   c2 = 1  d2 = 0

となります。a1~d1が、インクリメント・デクリメントで増減する値はそれぞれ変わりませんが、a2~d2は、異なる値となっています。これは、 前置が、演算の修了後、左辺の値に代入されるのに対し、後置が、代入の後に演算を行うということによる違いに基づくものです。インクリメントだけを例にとると、以下のようになります。

インクリメントの処理の内容
a=i++;a=i; i+=1;に該当
a=++i:i+=1; a=i;に該当

デクリメントに関しても、中身は同様です。このような処理は、かつてコンピュータの処理速度がさほど速くなかったり、メモリなどが十分になかったころ、リソースを少しでも節約するために用いられた手法です。しかし、 現在のコンピュータは、処理スピードも、メモリも十分に搭載していることから、こういった処理をプログラム中で書くことはほとんどなくなりました。

様々なfor文の記述方法

これで、基本的なfor文の使い方がわかったことと思います。次に、これを用いて色々な記述方法を見てみましょう。 list4-1の5行目を、表4-2のように、様々な値に変えてみましょう。

表4-2:for文の記述方法の例
記述方法 実行結果 説明
for(i = 0 ; i < 5 ; i++) 0 1 2 3 4 変数の値を1増加させる。5になると、ループを抜ける
for(i = -2 ; i <= 2 ; i++) -2 -1 0 1 2 -2から2まで、値を1つずつ増加させる
for(i = 0 ; i < 10 ; i+=2) 0 2 4 8 変数の値を2づつ増加させる。
for(i = 5 ; i >= 1 ; i--) 5 4 3 2 1 変数の値を1減少させる。5になると、ループを抜ける
for(i = 2 ; i >= -2 ; i--) 2 1 0 -1 -2 2から-2まで、値を1つずつ減少させる
for(i = 12 ; i > 0 ; i-=3) 12 9 6 3 変数の値を3づつ減少させる。0になると、ループを抜ける

この例では、intの場合をとりあげましたが、その他のデータ型でもforループを利用することは可能です。

forの二重ループ

サンプルプログラム

次に、forの二重ループ、もしくは、forのネスト処理を紹介します。この処理は、forループの中に更にforループを記述する二重の処理で、これもよく用いられるテクニックです。

list4-2:main.c
#include <stdio.h>

//	forの二重ループ
void main(){
	int i,j;
	for(i = 1; i<= 2; i++){
		for(j = 1; j <= 3; j++){
			printf("%d+%d=%d  ",i,j,i+j);
		}
		printf("¥n");
	}
}
実行結果
1+1=2 1+2=3 1+3=4
2+1=3 2+2=4 2+3=5

多重ループ

このプログラムでは、その側の変数iのループが、内側の変数jのループを繰り返しています。それぞれ、3回×2回で、6回のループが実現しています。(表4-3)

表4-3:i,jの関係性
i j i+j
1 1 2
2 3
3 4
2 1 3
2 4
3 5

このようにして、3重、4重のループを作ることも可能です。しかし、現実的に最も多いのは2重ループぐらいまでのようです。

while

サンプルプログラム

ループ処理を行うのは、for文だけではありません。while(ホワイル)文を用いることによっても実現可能です。まずは、以下のサンプルを見てください。

list4-3:main.c
#include <stdio.h>

//	iを用いたループ
void main(){
   int i = 0;
   while(i <= 5){	
	   printf("%d ",i);
	   i++;
   }
   printf("¥n");
}
実行結果
0 1 2 3 4 5

プログラムについて解説する前に、まずはwhile文の書式を見てみましょう。

whileの書式
whlie(条件式){
    処理
}

while文の書式

while文は、()内の条件が成り立つ間は、{}内に記述されている処理を繰り返します。つまり、4-3では、i<=5という条件が成り立っている間は中の処理が繰り返されることを意味します。 ()内で記述する条件式の記述方法は、if文の場合と同様のものです。

5行目で、iを0で初期化していますから、この段階でwhile文の条件である、「i<=5」は偽ですから、ループ処理に入ります。ループ内で、 iの値を表示すると共に、i++を行うことによって、iの値が増加しています。そのため、i==6となると、i<=5という命題は正しくない、つまり「偽」となります。ループから出ます。(図4-2)(表4-4)

図4-2.whileループの仕組み
whileループの仕組み
表4-4:iと条件の関係性
i 条件式 真/偽
1 1<=5
2 2<=5
3 3<=5
4 4<=5
5 5<=5
6 6<=5

見てわかるとおり、このサンプルは、list4-1と同等の処理です。しかし、for()文と違うのは、インクリメント・デクリメントといった処理や、初期値を設定する処理がループ内に存在しないことです。

do~while

サンプルプログラム

次に、ループ処理の3つ目である、do~while(ドゥ・ホワイル)文について説明しましょう。まずは、次のサンプルを入力してください。

list4-4:main.c
#include <stdio.h>

//	iを用いたループ
void main(){
   int i = 0;
   do{	
	   printf("%d ",i);
	   i++;
   }while(i <= 5);
   printf("¥n");
}
実行結果
0 1 2 3 4 5

do~while文の書式

実行結果は、list4-1,4-3と変わりません。(図4-3)ここで出てくる、do~while文の書式は、

図4-3.do~whileループの仕組み
do~whileループの仕組み
do~whileの書式
do{
    処理
}whlie(条件式); ← whileの後にセミコロンがついている。

実は、do~while文は、条件式の判定が後ろについているだけで、while文とまったく同じ働きをします。ただし、こちらは、whileの後に;(セミコロン)がついていますので、注意してください。

while文との違い

ここまでくると、「いったい、whileとdo~whileはどう違うのか?」という疑問をもたれる方もいることでしょう。実は、この二つには大きな違いがあるのです。まずは、以下のサンプルを実行してみてください。

list4-5:main.c
#include <stdio.h>

//	iを用いたループ
void main(){
	int i,num;
	printf("回数を入力:");
	scanf("%d",&num);	//	キーボードからループの回数を入力
	//	whileループで実行
	printf("whileで実行¥n");
	i = 1;
	while(i <= num){
		printf("*");
		i++;
	}
	printf("¥n");
	//	do~whileループで実行
	printf("do~whileで実行¥n");
	i = 1;
	do{
 		printf("*");
 		i++;
	}while(i <= num);
	printf("¥n");   
}

このプログラムは、コンソールから数字を入力し、その数だけ*を表示するプログラムです。そのため、入力した値により、実行結果は異なります。まず、5を入力すると、

実行結果1(5を入力した場合)
回数を入力:5
whileで実行
*****
do~whileで実行
*****

こういった場合は、while,do~while共に同じ結果になります。しかしここで0を代入すると、以下のようになります。

実行結果2(0を入力した場合)
回数を入力:0
whileで実行
do~whileで実行
*

whileの方は、何も表示されていません。しかし、do~whileの方は、1つだけ表示されています。 これは、whileの場合、iの値はもともと条件を満たしていないので、{}内の処理が実行されないのに対し、 do~whileの場合、まず{}の処理を実行してから条件判定をしているため、仮に条件式を満たしていなくても最低限1度は処理が実行されることによるものです。

無限ループ

サンプルプログラム

最後に、ループ処理でよく出てくる、無限ループという処理について説明しましょう。無限ループとは、その名のとおり、「際限なく繰り返されるループ」です。ここでは、while文を用いたサンプルを紹介します。

list4-6:main.c
#include <stdio.h>

//	iを用いたループ
void main(){
	int num;
	printf("負の値で、ループから抜けます。¥n");
	while(1){
		printf("数値を入力:");
		scanf("%d",&num);
		if(num < 0){
			//	ループから抜ける処理
			break;
		}
	}
	printf("終了¥n");
}
実行結果
数値を入力:9
数値を入力:3
数値を入力:42
数値を入力:-1
終了

プログラムを実行すると、「数値を入力:」と言う文字が出力され、コンソールからの数値の入力待ちになります。ここに様々な数値を入力していくことになります。 ここに正の数を入れる限り、同じことが繰り返されます。しかし、負の数を入れると、「終了」と表示されて、プログラムが終了します。

無限ループとbreak

while(1)とすると、基本的に処理は無限に繰り返されます。これは、条件式が偽の場合は、0、真の場合はそれ以外の値をとることを利用した方法で、無限に繰り返されます。 ただ、こういった無限ループでも、break(ブレイク)があると、ループから出ることができます。

無限ループは、forでも、do~whileでもできます。いずれも、breakで出ることができます。ただ、無限ループには、故意に行うものと、意図せずにできるものがあります。 故意に用いる場合は、このプログラムのように、必要な箇所にbreakを入れて、ループから出ることができるようになります。 しかし、そうでない場合は、強制的にプログラムを終了させる必要がある場合もあります。

以上で、順次処理分岐処理繰り返し処理という、アルゴリズムの三大要素を記述する方法について説明しました。 しかし、これだけではより複雑な実用プログラムを作るにはまだ不十分です。そこで、次からは、より複雑なプログラムを作るために必要な知識を身につけていくことにしましょう。

練習問題 : 問題4.