for文 ループ構文1

for文

ループとは、同じコードを繰り返し実行することです。
同じと言っても変数の値を変更したりして微妙に動作を変えることが多いです。

ループ構文でよく使われるのはfor文です。


#include <stdio.h>

int main()
{
    for (int i = 0; i < 10; i++)
    {
        printf("%d ", i);
    }
    getchar();
}
0 1 2 3 4 5 6 7 8 9 
for(初期化式; 条件式; 反復式){ 文 }
条件式が真の間、文を繰り返し実行する

for文は、ブロック内で指定した文を何度も実行することができます。
上記のコードでは10回の繰り返しが行われています。

for文の書式

初期化式

for文はまず最初に初期化式を一度だけ実行します。
ここで変数を宣言するとその変数はfor文の中で使用することができます。
for文が終了すると、その変数は使用できなくなります。

変数名は何でも構いませんが、「i」という一文字がよく使用されます。
ただ「i」では少し見づらいので別の名前を好む人もいます。

この変数iのように、一回ループする毎に値をひとつ増やす変数をループカウンタといいます。
ループカウンタは多くの場合でループの終了条件の判定のために使用されます。

条件式

次に、条件式を判定します。
この判定の結果が真の場合にブロック内の文を実行します。
サンプルコードでは、最初に宣言した変数iが10未満である場合に真となり、ループ文を実行します。

条件式が真の場合にが実行されます。
初期化式内で変数を宣言している場合、ここでその変数を使用できます。

反復式

文の実行が終わると、最後に反復式が実行されます。
サンプルコードでは変数iの値をひとつ増やしています。

反復式の実行後、再度条件式の判定に戻ります。
サンプルコードの条件式は「変数iが10より小さいか否か」なので、反復式が10回実行されて変数iの値が10になると条件判定は偽となり、ループの終了となります。

for文の初期化式内でint型の変数を宣言して使用していますが、この書き方ができるのは比較的新しいコンパイラに限られます。
古いコンパイラではエラーになります。
(Visual Studio 2015では問題ありません)

これは昔のC言語の規約では、変数の宣言は関数の先頭で行わなければならなかったためです。
古いコンパイラへも対応する場合は、変数の宣言をfor文から切り離して関数の先頭に記述します。


#include <stdio.h>

int main()
{
    int i;

    for (i = 0; i < 10; i++)
    {
        printf("%d ", i);
    }
    getchar();
}

ブロックの省略

ループしたい文が一行で済む場合はブロックの記述は省略できます。


for (int i = 0; i < 10; i++)
{
    printf("%d ", i);
}

//↓のように書ける

for (int i = 0; i < 10; i++)
    printf("%d ", i);

配列のすべての要素にアクセス

ループ文を使用すると配列の要素全体へのアクセスが容易になります。


#include <stdio.h>

int main()
{
	int nums[] = { 2, 4, 6, 8 };
	for (int i = 0; i < 4; i++)
		printf("%d ", nums[i]);

	getchar();
}
2 4 6 8 

ただし配列の要素よりも大きい値でループすると配列の要素の範囲外へのアクセスが発生してしまうので注意してください。

無限ループ

ループ文を使用する場合、無限ループになってしまうコードを書かないように気を付けましょう。
無限ループはいつまでたってもループを抜けることができない状態で、これが発生するとプログラムはフリーズしてしまいます。

以下は無限ループのサンプルです。


#include <stdio.h>

int main()
{
	//無限ループするので実行しないこと
    for (int i = 0; i < 10; i++)
    {
        printf("%d ", i);
        i--;
    }
    getchar();
}

このコードを実行するとフリーズするので実行しないでください。

ループ文の最後で変数iの値を1つ減らしています。
その後に反復式で変数iの値を増やしますが、結局のところ変数iの値は何回ループしても0のままで、条件判定は永久に真のままになってしまいます。

サンプルコードのようなわざとらしい無限ループは普通はあり得ませんが、コードが複雑になるとミスしてしまう可能性はあります。
for文は書式通りに書けば無限ループが発生しにくくなっていますが、次ページで紹介するwhile文ではうっかり無限ループとなるコードを書くことがあります。

ちょっと変則的なfor文

for文の丸括弧内の三つの式は必ずしも書かなければならないものではありません。
以下のようなコードでもきちんと動作します。


#include <stdio.h>

int main()
{
    int i = 0;
    for (;;)
    {
        printf("%d ", i);
        if (i >= 9)
        {
            break;
        }
        i++;
    }
    getchar();
}

このコードの実行結果は最初のサンプルコードと同じです。

for文の丸括弧内には;;とセミコロンが二つ書かれているだけで中身が省略されています。
for文の文法上、丸括弧内には式が最低ふたつ必要なので、文末を示すセミコロンを書くことで、何もしない空の式を二つ指定しているのです。
反復式の最後にセミコロンを書くとエラーになるので、セミコロンを三つ書いてはいけません。

ループ文では変数の中身の表示後、変数iの値を調べ、9以上の場合はbreak文を実行しfor文を抜けます。
break文はswitch文の時にも登場しましたが、現在のループ文を抜けることもできます。
変数iが9未満の場合は変数iの値をひとつ増やし、ループ文の先頭に戻ります。

反対に、このような書き方もできます。


#include <stdio.h>

int main()
{
    int i = 0;
    for (int i = 0, j = 0; i < 10; i++, j++)
    {
        printf("%d,%d\n", i, j);
    }
    getchar();
}

コンマで区切ることで、初期化式や反復式で複数の処理を行っています。

これらの書き方は見た目にわかりにくくなることがあるのであまり多用しない方がいいかもしれません。
ただ、より簡潔にコードが書ける場合があるので知っておいて損はないでしょう。

double(float)型を終了条件に使用する際の注意

for文などのループ文にはループ終了条件の判定があります。
ここにdouble型やfloat型などの小数点を含む値を使用すると意図しない結果となることがあります。


#include <stdio.h>

int main()
{
    for (float f = 0.0f; f <= 1.0f; f += 0.1f)
    {
        printf("%f\n", f);
    }
    getchar();
}

小数点を含む値はコンピューターでは正確に表すことができず、小さいながらも誤差が生じます。
普通は問題ない程度の誤差ですが、ループの条件判定に使用するとその誤差のためにループの回数が意図したよりも多い/少ない、といったことが起こり得ます。

以下は誤差による誤動作が明確に表れる例です。


#include <stdio.h>

int main()
{
	//このコードは無限ループする可能性が高いので実行しないこと
    for (float f = 0.0f; f != 1.0f; f += 0.1f)
    {
        printf("%f\n", f);
    }
    getchar();
}

このコードの意図は、条件式が真の間ループするのだから、変数fに0から0.1ずつ加算していき、1.0の時に条件式が偽になってループを抜けるだろう、というものです。
しかし誤差のために実際にはf == 1.0fが成立することはなく、ループを抜けることができないのです。

これはif文などのほかの条件判定でも同じことが言えるので、注意してください