7.

C++のfor文の使い方|基本構文・範囲for・break/continue

編集

C++のfor文は、回数や範囲があらかじめ決まっている繰り返し処理を簡潔に書くための制御構文です。ループ変数の初期化・継続条件・更新をひとまとめに書けるため、決まった回数の反復や配列・コンテナの走査でよく使われます。

この記事の要点
  • 基本構文は for (初期化; 条件; 更新) { 処理 } の3つの式で構成される。
  • 条件が真の間だけ { } 内が繰り返され、各回の終わりに更新式が実行される。
  • C++11以降は、要素を順に取り出す範囲for for (型 x : コンテナ) も使える。
  • 回数が決まっている処理に向き、回数が不定の処理には while 文が向く。
  • break で途中終了、continue で次の回へスキップできる。
  • 条件の境界(オフバイワン)やループ変数の型は、バグの原因になりやすい注意点。

 

基本構文

for文は「初期化」「条件」「更新」の3つの式をセミコロンで区切って書き、波かっこ { } の中に繰り返したい処理を記述します。

for (初期化; 条件; 更新) {

    // 繰り返したい処理

}

もっとも典型的な書き方は、0から数えるカウンタ変数を使う形です。次の例は i を 0、1、2、3、4 と変化させ、合計5回繰り返します。

for (int i = 0; i < 5; i++) {

    cout << i << "\n";

}

 

各部の役割

for文のかっこ内の3つの式は、それぞれ実行されるタイミングが異なります。

部分 役割と実行タイミング
初期化int i = 0ループ開始時に1回だけ実行。カウンタ変数の用意や初期値の設定を行う。
条件i < 5毎回の繰り返し前に評価。真なら本体を実行し、偽になればループを終了する。
更新i++本体を1回実行し終えるたびに実行。多くはカウンタを進める。

実行の流れは「初期化 → 条件判定 → 本体 → 更新 → 条件判定 → …」の順になります。条件が最初から偽であれば、本体は一度も実行されません。なお初期化で宣言した変数(上の例の i)の有効範囲はそのfor文の中だけで、ループを抜けると参照できなくなります。

 

範囲for文(C++11以降)

配列やコンテナの全要素を順番に処理するだけなら、カウンタを使わずに書ける範囲for文(範囲ベースforループ)が便利です。C++11から導入された構文で、要素を1つずつ変数に取り出します。

int data[] = {10, 20, 30};

for (int x : data) {

    cout << x << "\n";

}

添字(インデックス)を意識せずに済むため、走査時の境界ミスが起こりにくくなります。要素をコピーせずに扱いたい場合や要素を書き換えたい場合は、for (int& x : data) のように参照で受け取る書き方もあります。一方、何番目の要素かを知る必要がある処理では、従来のカウンタ方式のfor文が適しています。

 

while文との違い

for文とwhile文はどちらも繰り返しを表しますが、初期化・条件・更新の書く場所が異なります。for文はこの3つを1行にまとめられるため、繰り返し回数があらかじめ決まっている処理に向いています。while文は条件だけを書く形で、回数が不定で「ある条件が成り立つ間ずっと続けたい」処理に向いています。

// for文

for (int i = 0; i < 5; i++) { /* 処理 */ }

 

// 同じ動作を while文で書いた場合

int i = 0;

while (i < 5) {

    // 処理

    i++;

}

どちらでも同じ繰り返しを書けますが、カウンタの管理が一箇所にまとまるfor文のほうが、回数指定のループでは更新式の書き忘れを防ぎやすい利点があります。

 

ネストと配列の走査

for文の中にfor文を入れるネスト(入れ子)もできます。二次元配列の走査や、行と列の組み合わせを扱う処理でよく使われます。次の例は2行3列の配列をすべて出力します。

int table[2][3] = {{1, 2, 3}, {4, 5, 6}};

for (int row = 0; row < 2; row++) {

    for (int col = 0; col < 3; col++) {

        cout << table[row][col] << " ";

    }

    cout << "\n";

}

外側のループが1回進むごとに、内側のループが最後まで回ります。配列とfor文を組み合わせた走査の詳しい考え方は、配列とfor文もあわせて参考にしてください。

 

break と continue

ループの途中で流れを変えたいときは、breakcontinue を使います。

  • break:その時点でループを完全に抜けます。目的の値が見つかった時点で探索を打ち切る場合などに使います。
  • continue:その回の残りの処理を飛ばし、次の繰り返しへ進みます。条件に合わない要素だけスキップしたい場合などに使います。

for (int i = 0; i < 10; i++) {

    if (i == 5) break;     // 5でループ終了

    if (i % 2 == 0) continue; // 偶数は飛ばす

    cout << i << "\n"; // 1, 3 が出力される

}

なお break はネストしたforのうち、それが書かれている内側のループ1つだけを抜けます。外側まで一度に抜けることはできない点に注意してください。

 

無限ループ

条件式を空にすると、条件が常に成立し続ける無限ループになります。3つの式すべてを省略した for (;;) がその代表的な書き方です。意図して使う場合は、ループ内の break などで抜ける条件を必ず用意します。

for (;;) {

    // 何らかの処理

    if (終了条件) break; // 抜ける手段が必要

}

抜ける条件を書き忘れると、プログラムが終わらなくなります。意図しない無限ループは、次の落とし穴とも深く関わります。

 

落とし穴と注意点

起こりやすい問題 原因と対処
境界の数え間違い(オフバイワン)要素数 n の配列で i <= n と書くと範囲外まで参照してしまう。0始まりなら i < n が基本。条件が <<= か、開始が0か1かを毎回確認する。
ループ変数の型と範囲扱う値が大きい場合、int では桁あふれ(オーバーフロー)が起こり得る。コンテナの要素数を扱うなら size_t など、用途に合う型を選ぶ。
意図しない無限ループ更新式の書き忘れや、条件が永遠に真のままになることで発生する。カウンタが本当に終了方向へ進むか、条件が偽になり得るかを確認する。

 

よくある質問

Q. 範囲for文と、従来のfor文はどう使い分ければよいですか。
A. 全要素を頭から順に処理するだけなら、添字ミスが起きにくい範囲for文が簡潔です。何番目の要素かを使いたい、一部の要素だけ処理したい、添字を計算に使うといった場合は、カウンタを持つ従来のfor文が適しています。

Q. for文の初期化で宣言した変数は、ループの外でも使えますか。
A. 使えません。for (int i = 0; ...) のように初期化部分で宣言した変数の有効範囲はそのfor文の中だけです。ループを抜けた後も値を参照したい場合は、for文の前で変数を宣言しておきます。

Q. ネストしたfor文から、外側のループまで一度に抜けたいときは。
A. break は内側の1つのループしか抜けません。外側まで抜けたい場合は、フラグ用の変数を使って外側の条件で判定する、処理を関数に分けて return で抜けるなどの方法を取ります。

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. コメントアウト
  2. 文字列の結合/連結
  3. 変数の宣言
  4. 定数の宣言
  5. if文
  6. if文の論理演算子
  7. for文
  8. データ型(文字列以外)
  9. データ型(文字列)
  10. 配列とfor文
  11. 配列の要素数
  12. 多次元配列とfor文
  13. 多次元配列の要素数
  14. 関数の定義と呼び出し

最近更新/作成されたページ