WisdomSoft - for your serial experiences.

3.6 for文

for 文について解説します。for 文は繰り返し回数を数えるための変数の初期化やインクリメントを構文の中で記述できます。

3.6.1 カウンタ制御付きループ

基本的に、繰り返し処理は while 文さえ知っていれば十分使うことができますが、多くのプログラマはこれから紹介する for 文を愛用しています。for 文は、条件式のほかにカウンタ変数の初期化とカウント処理を管理してくれる便利な制御文です。

for文
for (初期化式 ; 条件式 ; ループ式) 

条件式が真であれば、文を繰り返し実行するという点においては while と同じです。初期化式は for ループが開始される前に一度だけ評価される式で、通常はループ制御に用いるためのカウンタ変数などを初期化するために使います。ループ式は、文を繰り返す度に評価される式で、カウンタ変数をインクリメントしたり、デクリメントするために使われます。これは、次の while 文を用いたプログラムと同じです。

初期化式
while(条件式) {
	文
	ループ式
}

多くの場合、while 文で繰り返し処理を行う場合も、ループ制御のためにカウンタを用いた上記したような構造になります。for 文はこれらの構造を完全な構文として義務づけているため、ほとんどのプログラマは積極的に for 文を利用しています。

さらに for 文は、初期化式、条件式、ループ式のいずれも省略することが可能です。条件式を省略した場合は常に真であると解釈されるため、無限ループになります。この場合は break 文を用いて抜け出すなどの対策が必要になります。ただし、省略する場合もセミコロン ; を省略することはできません。例えば、全ての式を省略した for 文は for ( ; ; ) { ... と記述する必要があります。

コード1
#include <stdio.h>

int main() {
	int iMax , iCount;
	printf("繰り返す回数を入力してください>");

	for(scanf("%d" , &iMax) , iCount = 0 ; iCount < iMax ; iCount++)
		printf("%d 回目の繰り返しです\n" , iCount);
	return 0;
}
実行結果
コード1 実行結果

コード1は、入力された回数だけ for 文を用いて表示処理を繰り返す単純なプログラムです。しかし、このプログラムは少し意地悪なソースになっています。それは、for 文の初期化式の部分 scanf("%d" , &iMax) , iCount = 0 です。この一文にはカンマ , が2ヶ所ありますが、実はこれらは同じカンマでも、C言語の構文上異なる性質を持っています。つまり異質の機能を持っています。

scanf("%d" , &iMax) , iCount = 0 という式における2つのカンマの違いを答えなさいという問いに、正しく答えられるプログラマはそう多くないでしょう。実は、カンマには単純な区切りとして用いる場合と、式に演算子として用いる場合があります。scanf("%d" , &iMax) という文の中にあるカンマは演算子ではありません。これは区切り記号です。

これに対して、式の中で用いられた場合は順次評価演算子(又はカンマ演算子と呼ばれる)として機能します。このカンマの使い方は非常に希少的です。カンマによって分けられた式は、必ず左から右に向かって評価されます。順次評価演算子の演算結果は、右オペランドと同じ値と型を持ちます。オペランドにはあらゆる型を指定でき、オペランド間の型変換は行われません。

for 文の初期化式やループ式で複数の式を評価したい場合は、コード1のように順次評価演算子を用いて複数の式を指定することができるのです。

しかし、一般論として順次評価演算子を積極的に使うことは避けるべきだと考えられています。お互いに強く関連している構文や、複数行の計算をどうしても1つの文として記述しなければならないような場合に用いるべきでしょう。例えば、二つの変数の内容を交換するプログラムを作る場合などに利用するのも適当でしょう。

コード2
#include <stdio.h>

int main() {
	int iVar1 = 100 , iVar2 = 200;
	iVar2 ^= iVar1 , iVar1 ^= iVar2 , iVar2 ^= iVar1;
	printf("iVar1 = %d : iVar2 = %d\n" , iVar1 , iVar2);

	return 0;
}
実行結果
コード2 実行結果

このプログラムは、変数 iVar1 と iVar2 の値を交換して、その結果を表示するというものです。値の交換アルゴリズムは順次評価演算子を用いて1つの式として表現しています。ところで、このプログラムでも少し意地悪な仕掛けをほどこしています。通常は変数の値の交換は、一時保存用変数を定義して次のようにして行われるのが一般的でしょう。

iTmp = iVar1 , iVar1 = iVar2 , iVar2 = iTmp;

しかし、コード2では、排他的論理和の性質をうまく利用して、一時保存用の変数を用意することなく交換を行っています。本題からそれましたが、このように工夫することで、プログラムの要求に適した処理を実現することができるようになるでしょう。

話を本題に戻します。コード2のように順次評価演算子を使ってひとつの文として複数の式を評価させることができました。しかし、やはり最初に言ったように順次評価演算子を積極的に使うことは避けるべきであり、この場合も、単一の文として表現することに意味はありません。むしろ次のように記述する方が一般的でしょう。

iVar2 ^= iVar1 ; iVar1 ^= iVar2 ; iVar2 ^= iVar1;

これは、ひとつの式ではなく、セミコロンによって3つの文として分割されていますが、これで問題が生じることはありません。むしろ、この書き方のほうが一般的なので、多くのプログラマにとってはこちらの方が読みやすいと思われます。

for 文も while と同様に入れ子構造にすることができます。もちろん break 文や continue 文を使うこともできます。複雑な計算や処理には、必ずといってよいほど繰り返し処理が必要になるため for 文や while 文の使い方はしっかりとマスターしましょう。次のプログラムは、while 文で作った九九の表を for 文で作成したものです。

コード3
#include <stdio.h>

int main() {
	int iOp1 , iOp2;

	for(iOp1 = 1 ; iOp1 < 10 ; iOp1++) {
		for(iOp2 = 1 ; iOp2 < 10 ; iOp2++) {
			printf("%2d " , iOp1 * iOp2);
		}
		printf("\n");
	}
	return 0;
}
実行結果
コード3 実行結果

while を使った場合に比べて、行数が少なくスマートになったと感じられると思います。while の場合は複合文の内部でインクリメントや初期化などの処理を行う必要がありましたが、for を使えば、これらを初期化式やループ式にまとめることができます。多くのプログラマが積極的に for を使いたがる理由が分かったと思います。