C言語のfor文入門:決まった回数(10回など)だけ処理を繰り返すループの書き方とサンプルコード

C言語で「同じ処理を10回繰り返す」といった、回数が決まっている反復にはfor文が最適です。

この記事では、0開始・未満条件の基本形から、1〜10のような区間の数え上げ、配列全走査、逆順(カウントダウン)、break/continue、型とスコープの注意点、よくあるミスまで、実用的なサンプルとともに丁寧に解説します。

for文とは

回数が決まった反復に向く制御構文

for文は、初期化・継続条件・更新の3つをひとまとめに記述できるため、決まった回数のループや、配列・文字列の走査に最もよく使われます。

条件が偽になった時点でループを終了します。

構文の基本

3つの式の意味

  • 初期化: ループ開始時に一度だけ評価され、カウンタ変数の初期値を設定します。
  • 条件: ループ継続の判定を毎回行います。偽になったら終了します。
  • 更新: 各周回の末尾で評価され、カウンタを進めたり減らしたりします。
C言語
for (初期化; 条件; 更新) {
    /* 繰り返したい処理 */
}

波括弧の省略

本体が1文のみなら{}は省略可能ですが、可読性・保守性のため基本的に{}を付けることをおすすめします。

基本形(10回繰り返す)

0開始・未満条件が定番

回数が決まっているときは、カウンタを0から始め、条件を「未満」にするのが定番です。

これにより「0〜(回数-1)」の範囲が素直に表現できます。

C言語
#include <stdio.h>

int main(void) {
    for (int i = 0; i < 10; i++) {
        printf("i = %d\n", i); // 0~9で10回
    }
    return 0;
}
実行結果
i = 0
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
i = 8
i = 9

なぜ「未満」が安全か

上限を「未満」にすると、配列の要素数nに対して0 <= i < nという自然な条件が書け、配列外参照のバグを避けやすくなります。

1から10まで数えたい場合

開始値と条件を付け替える

「1〜10」のように人間の数え方で出力したい場合は、開始値を1、条件を「<=(以下)」にします。

C言語
#include <stdio.h>

int main(void) {
    for (int i = 1; i <= 10; i++) {
        printf("%d回目\n", i); // 1~10で10回
    }
    return 0;
}
実行結果
1回目
2回目
3回目
4回目
5回目
6回目
7回目
8回目
9回目
10回目

Off-by-one(±1ミス)に注意

  • 0〜9の10回: for (int i = 0; i < 10; i++)
  • 1〜10の10回: for (int i = 1; i <= 10; i++)

条件演算子の向きを取り違えると1回多い/少ないバグになりやすいです。

回数を変数・定数で指定する

マジックナンバーを避ける

const定数で指定

回数をコード内に直接書くのではなく、意味のある名前の定数にしましょう。

C言語
#include <stdio.h>

int main(void) {
    const int N = 5; // 必要に応じて意味のある名前に
    for (int i = 0; i < N; i++) {
        printf("%d ", i);
    }
    printf("\n");
    return 0;
}
実行結果
0 1 2 3 4

マクロでビルド時に固定

ビルド時に確定したい場合はマクロも有効です。

C言語
#include <stdio.h>
#define N 5

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

引数や入力で可変回数にする

外部から回数を与えるとテストや再利用がしやすくなります。

入力値には上限チェックを設けましょう。

C言語
#include <stdio.h>

int main(void) {
    int n;
    if (scanf("%d", &n) != 1) return 1;     // 入力失敗
    if (n < 0 || n > 1000000) return 1;     // 過大・不正入力を拒否

    for (int i = 0; i < n; i++) {
        // ここに処理
    }
    return 0;
}

上限チェックの意義

極端に大きな回数は処理時間やリソースを圧迫します。

ユーザー入力に従う場合は妥当な上限を設けるのが実務では必須です。

配列や文字列の長さで回す

配列の全要素を処理する

C配列は長さ情報を持たないため、自分で要素数を求めます。

静的配列ならsizeofで安全に計算できます。

C言語
#include <stdio.h>

int main(void) {
    int a[] = {1, 2, 3, 4, 5};
    size_t n = sizeof a / sizeof a[0]; // 要素数

    for (size_t i = 0; i < n; i++) {
        printf("%d\n", a[i]);
    }
    return 0;
}
実行結果
1
2
3
4
5

可変長配列・ポインタには注意

関数引数として配列を受け取るときは「配列はポインタに退化」するため、sizeofで要素数は分かりません。

要素数を別引数で渡すのが基本です。

文字列の長さで回す

strlenで長さ(終端のヌル文字を除く)を取得し、その長さだけ回します。

C言語
#include <stdio.h>
#include <string.h>

int main(void) {
    const char s[] = "abc";
    size_t len = strlen(s);

    for (size_t i = 0; i < len; i++) {
        printf("%c", s[i]);
    }
    printf("\n");
    return 0;
}
実行結果
abc

カウントダウン(逆順)ループ

intのインデックスで逆順

intの範囲なら「0以上」を条件にしてカウントダウンできます。

C言語
#include <stdio.h>

int main(void) {
    for (int i = 9; i >= 0; i--) { // 0~9の逆順で10回
        printf("%d ", i);
    }
    printf("\n");
    return 0;
}
実行結果
9 8 7 6 5 4 3 2 1 0

size_t(符号なし)の安全な逆順

配列長やstrlenと相性の良いsize_tは符号なし型です。

そのためi >= 0は常に真になり危険です。

慣用的に「for (size_t i = n; i-- > 0; )」と書きます。

C言語
#include <stdio.h>

int main(void) {
    int a[] = {10, 20, 30, 40};
    size_t n = sizeof a / sizeof a[0];

    // i は n-1 から 0 へ
    for (size_t i = n; i-- > 0; ) {
        printf("%d ", a[i]);
    }
    printf("\n");
    return 0;
}
実行結果
40 30 20 10

なぜ「i– > 0」なのか

後置デクリメントは比較評価の後に減少するため、iが0の周回は実行されず、in-1から0まで安全に1回ずつ回ります。

ループ変数の型とスコープ

インデックスとサイズはsize_tが基本

配列の要素数、strlensizeofsize_t型を返します。

インデックスもsize_tに合わせると、型不一致や符号なし/ありの比較が原因の警告や不具合を避けやすくなります。

printfsize_tを出力する場合のフォーマット指定子は%zuです。

C99以降はfor内で宣言可能

C99以降ではfor (int i = 0; …)のようにループ変数をその場で宣言できます。

古い規格(C90など)ではブロック先頭で事前宣言が必要です。

C言語
#include <stdio.h>

int main(void) {
    for (int i = 0; i < 3; i++) { // C99以降
        printf("%d ", i);
    }
    printf("\n");
    // ここでは i は見えない(スコープはfor文の内部)
    return 0;
}
実行結果
0 1 2

スコープはforのブロック内

C99以降では、ループ変数はfor文のブロック内に限定されます。

同名の変数を別のループで再利用しても衝突しません。

読みやすさ・誤用防止のためにもスコープは狭く保ちましょう。

break / continue の最小例

特定の条件でスキップ・打ち切り

continueはその周回の残りをスキップ、breakはループ全体を打ち切ります。

C言語
#include <stdio.h>

int main(void) {
    for (int i = 0; i < 10; i++) {
        if (i == 3) continue; // 3だけスキップ
        if (i == 8) break;    // 8で打ち切り(0,1,2,4,5,6,7まで)
        printf("%d ", i);
    }
    printf("\n");
    return 0;
}
実行結果
0 1 2 4 5 6 7

多用は避ける

breakcontinueは便利ですが、条件が散らばると読みづらくなります。

複雑化する場合は条件の整理や関数抽出を検討してください。

よくあるミスと注意点

Off-by-one(±1ミス)

  • やりたいこと: 0〜9を10回
    • 正: for (int i = 0; i < 10; i++)
    • ありがちな誤り: i <= 10(11回になる)
  • やりたいこと: 1〜10を10回
    • 正: for (int i = 1; i <= 10; i++)
    • ありがちな誤り: i < 10(1〜9で9回)

型の不一致

配列長やstrlensize_tです。

intと比較したり、符号なしと符号ありを混在させると警告やバグの原因になります。

インデックスはsize_t、出力には%zuを使いましょう。

符号なしでの逆方向ループ

size_t i; for (i = n - 1; i >= 0; i--)は停止しません(i >= 0が常に真)。

for (size_t i = n; i-- > 0; )」や「for (size_t i = n; i > 0; i--) { /* i-1 を使う */ }」など安全な条件に書き換えます。

ループ変数の更新忘れ・本体での改変

更新をforの第3式に集約し、本体でループ変数を変更しないのが定石です。

本体での加減はバグの温床になります。

回数が大きすぎる

ユーザー入力や外部データに依存する回数は、妥当な上限を設けましょう。

DoS的な極端入力で処理が止まるのを防げます。

まとめ

固定回数の反復は、0開始・未満条件の「for (int i = 0; i < N; i++)」が基本形です。

区間を1〜10のようにしたい場合は開始値と条件(<=)を調整します。

配列や文字列の走査にはsize_tを用い、逆順では「i-- > 0」や「i > 0i-1」といった安全な条件を選びましょう。

可読性と安全性のため、マジックナンバーを避け、上限チェックやスコープの短縮、型の整合性に注意して書くことが大切です。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!