ユーニックス総合研究所

  • home
  • archives
  • c-for

C言語のfor文の書き方【繰り返し文】

  • 作成日: 2020-08-07
  • 更新日: 2023-12-25
  • カテゴリ: C言語

C言語の繰り返し処理

C言語には繰り返し処理が書けるfor文という文があります。
繰り返し処理はループ処理とも呼ばれますが、ループ処理を書きたい時にこのfor文を使います。
ループ処理とは無限ループや定数回ループなどのことを言います。

例えば↓は0から4より下までカウント変数をカウントし、画面にカウント変数の中身を表示するコードです。

#include <stdio.h>  

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

    return 0;  
}  

↑のコードを実行すると↓のような結果になります。

0  
1  
2  
3  

for文を使ってループ処理を書けるようになると、大量の情報を処理できるようになります。
for文はプログラミングのだいご味と言ってもいいかもしれません。
パソコンに大量の処理をさせたい時はこのfor文が必ず顔を出します。
それぐらいポピュラーな文です。

関連記事

目が覚めるC言語のdo-while文の使い方【ループ処理、初心者向け】
明快!C言語のcontinue文の使い方
君はまだC言語のdefineのすべてを知らない【マクロ、プリプロセス】
プログラミングのポインタをわかりやすく解説【C言語】
コードで見るC言語とC++の7つの違い

目が覚めるC言語のdo-while文の使い方【ループ処理、初心者向け】
明快!C言語のcontinue文の使い方
君はまだC言語のdefineのすべてを知らない【マクロ、プリプロセス】

for文の構造

for文は↓のような構造をしています。

for (初期化; 条件判定; 更新) {  
    処理;  
}  

まずfor文は初期化部分でループの状態を初期化します。
初期化が終わると次に条件判定をします。
そして条件判定が終わると、今度は処理を実行します。
処理を一回実行したら、今度はループの更新を行います。
更新が終わったら再び条件判定を行って処理を実行します。

つまり

  1. 初期化
  2. 条件判定(真なら継続、偽なら終了)
  3. 処理
  4. 更新
  5. 2に戻る

こういうことになります。
2に戻るというところがミソで、ここがループになってますね。
そしてfor文は条件判定が真ならループを継続し条件判定が偽ならループを終了します

for文の初期化

for文の初期化部分を見てみます。

for (初期化; 条件判定; 更新) {  
    処理;  
}  

ここには変数を定義したり、計算処理を書いたり、関数を呼び出したりできるところです。
たとえばループで使うカウント変数を定義してみます。

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

↑の場合、int i = 0; というところが初期化部分で、ここでカウント変数iを定義しています。
この部分で定義した変数はfor文のブロック内で使うことが出来ます。
for文のブロックとは {}で囲まれた部分です。

ここの変数定義は複数可能です。
複数定義する場合は、カンマ(,)で区切ります。

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

ただし複数の変数を定義する場合は、型を統一しておく必要があります。
つまり、同じ型の変数しか初期化部分では定義できません。

また、初期化部分ではfor文の外で定義した変数を初期化したりも出来ます。

int i;  

for (i = 0; i < 4; i++) {  
    printf("%d\n", i);  
}  

関数を呼び出すことも出来ます。

for (func();;) {  
}  

初期化部分は省略することも可能です。
その場合、初期化部分のセミコロン(;)は省略できません。

int i = 0;  

for (; i < 4; i++) {  
    printf("%d\n", i);  
}  

for文の条件判定

条件判定ではfor文を継続するか終了するか判定します

for (初期化; 条件判定; 更新) {  
    処理;  
}  

ここにはC言語の式を書くことが出来ます。
比較式を書いたり、

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

for (int i = 0; i != 4; i++) {  
    printf("%d\n", i);  
}  

for (int i = 0; i < 4 && i % 2 == 0; i++) {  
    printf("%d\n", i);  
}  

値を参照したり、

for (int i = 4; i; i--) {  
    printf("%d\n", i);  
}  

関数を呼び出したりできます。

for (int i = 0; check(i); i++) {  
    printf("%d\n", i);  
}  

条件判定文が真ならループは継続し、偽ならループが終了します。
ループが終了した場合、for文のブロックの終了地点に処理が移動します。

また、for文の条件判定は省略可能です。

for文の処理

for文の処理部分です。

for (初期化; 条件判定; 更新) {  
    処理;  
}  

ここにはありとあらゆる制御文や変数宣言&定義、関数呼び出しなどを書くことが出来ます。
ブロック({})の中に書けるものはここにも書くことが出来ます。

for (int i = 0; i < 4; i++) {  
    switch (i) {  
    case 0: printf("zero\n"); break;  
    case 1: printf("one\n"); break;  
    default: printf("good\n"); break;  
    }  

    int item = get_item(i);  
    printf("item %d\n", item);  
}  

繰り返し処理の具体的な処理内容をここに書くのが一般的です。

break文でfor文から抜ける

処理の中にbreak文を書くと、そのループから抜けることができます。

for (int i = 0; i < 4; i++) {  
    break;  
}  

↑の場合、break文に達した時点でループが終了します。
for文が入れ子になっている場合は、break文を記述したブロックのfor文から抜けます。

// 外側  
for (int i = 0; i < 4; i++) {  

    // 内側  
    for (int j = 0; j < 4; j++) {  
        break;  
    }  
}  

↑の場合、break文は「内側」のfor文からは抜けますが、「外側」のfor文からは抜けません。

また、break文はif文やブロック文の中でも有効です。
その場合、ifの外側にあるfor文からブレークします。

for (int i = 0; i < 4; i++) {  
    if (i == 2) {  
        break;  
    }  
}  

↑の場合、カウント変数は0, 1とカウントされますが、2になった時点でループからブレークします。

continue文でループをスキップする

処理を飛ばしたい場合はcontinue文を使うとループを1回分スキップ出来ます。

for (int i = 0; i < 4; i++) {  
    if (i == 0) {  
        continue;  
    }  

    printf("%d\n", i);  
}  

↑の場合、カウント変数が0の時はcontinue文以降の処理をループ1回分スキップ(実行しない)します。
↑の実行結果は↓のようになります。

1  
2  
3  

continue文もif文の中でも有効です。continue文もif文の外側にあるfor文に作用します。
もちろんcontinue文単体でも書くことが出来ます。

for (int i = 0; i < 4; i++) {  
    continue;  
    printf("%d\n", i);  
}  

↑の場合、ループ処理の先頭でcontinue文が実行されるので、ループ内の処理は毎回スキップされます。
よって何も出力されません。

for文の更新

更新部分では、変数などの値を更新したりします。
ここにはC言語の式を書くことが出来ます。

for (初期化; 条件判定; 更新) {  
    処理;  
}  

たとえばループ処理が実行されるたびに、カウント変数をインクリメントしたい場合は↓のように書きます。

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

更新部分の式は複数書けます。その場合はカンマ(,)で区切ります。

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

また、更新部分は省略可能です。

よく使われるfor文~無限ループ

for文の初期化、条件判定、更新部分は省略可能ですが、これを全部省略するとどうなるのでしょうか?

for (;;) {  
}  

泣き顔みたいになってしまいましたね。

🦝 < つらいんやな

じつはこのfor文、ただ処理を無限に繰り返すだけの無限ループになります。
無限ループはwhile文を使った方法もよく知られています。

while (1) {  
}  

これとどっちが使われるかと言うのは、書き手の好みによります。
なので両方とも覚えておきましょう。

無限ループについてもっと詳しく

無限ループについてもっと詳しく見てみましょう。

for (;;) {  
}  

このfor文のループは永遠に続き止まりません。
このような無限ループに使いどころがあるのでしょうか?

それが無限ループはプログラミングでは非常によく使われるループです。
たとえばゲーム処理を考えてく見てください。
ゲームは電源が入っている間永遠とタイトル画面が出たりゲーム画面が出たりします。
このようなループ処理にも無限ループが使われている可能性が高いです。

無限ループから抜けるにはCtrl + Cなどを入力する必要があります。
プログラミングのバグでも無限ループになることはあるので覚えておいた方がいいでしょう。

for文を使ったプログラムのサンプル

for文を使ったプログラムのサンプルとしてはバブルソートなどがあげられます。

/**  
 * 原始的なバブルソートを実行する  
 *   
 * @param[in|out] ary 配列  
 * @param[in] arylen 配列の長さ  
 */  
void bubble_sort(int *ary, int arylen) {  
    // 外側のfor文  
    for (int i = 0; i < arylen - 1; i += 1) {  
        // 内側のfor文  
        for (int j = 0; j < arylen - 1; j += 1) {  
            // 隣り合う要素同士を比較  
            if (ary[j] > ary[j + 1]) {  
                // スワップの実行  
                int tmp = ary[j];  
                ary[j] = ary[j + 1];  
                ary[j + 1] = tmp;  
            }  
        }  
    }  
}  

↑のバブルソートはfor文を2重(入れ子)にして使っています。
このようにfor文は入れ子にすることで複雑な処理を実現できます。
しかし計算オーダーが悪化することが多いため、速度が必要な処理では注意する必要があります。
できるなら1重のfor文で完結させた方が速度の出るプログラムは作れるでしょう。

まとめ

for文は↓のような構造になっています。

  1. 初期化
  2. 条件判定(真なら継続、偽なら終了)
  3. 処理
  4. 更新
  5. 2に戻る

for文を使えるようになると色々なプログラムを作れるようになるので、ぜひ覚えておきましょう。