C++のrange-based for文(範囲ベースforループ)入門!配列やvectorの回し方を初心者向けに徹底解説
生徒
「C++で配列の中身を全部表示したいんですけど、もっと簡単に書く方法はありませんか?iを使って数えるのが少し大変で……。」
先生
「それなら『range-based for文(範囲ベースfor文)』がぴったりですよ。C++11というバージョンから登場した、とても便利な書き方です。」
生徒
「レンジベース……?難しそうな名前ですね。パソコンを触ったことがない僕でも使えますか?」
先生
「大丈夫ですよ!『箱の中身を端から順番に取り出す』というイメージだけで理解できます。さっそく基本から一緒に学んでいきましょう!」
1. range-based for文(範囲ベースfor文)とは?
C++のプログラミングにおいて、データの集まり(配列やリストなど)の要素を一つずつ順番に処理することは非常に頻繁にあります。これまでの古い書き方では「0番目から順番に、データの数だけ繰り返す」という指定が必要でしたが、range-based for文(範囲ベースfor文)を使えば、もっと直感的に「すべての要素に対して処理を行う」と記述できます。
プログラミング未経験の方にとって、ループ処理(繰り返し)は最初の壁になりやすいですが、この範囲ベースfor文は「中身が何個あるか」をプログラムが自動で判断してくれるため、書き間違いによるミスが減り、コードがスッキリと読みやすくなるのが大きなメリットです。SEOの観点からも、モダンなC++開発では必須の知識と言えるでしょう。
2. プログラミング初心者でもわかる「繰り返し」のイメージ
まずは、パソコンやプログラミングに慣れていない方向けに、身近な例えで解説します。例えば、目の前に「5つのリンゴが入ったカゴ」があると想像してください。このカゴの中にあるすべてのリンゴに「合格シール」を貼る作業をプログラムで作るとしましょう。
従来のやり方(通常のfor文)では、「カゴの中を確認して、1個目を取り出す。シールを貼る。次に2個目を取り出す。シールを貼る……」という風に、何個目かを常に意識する必要がありました。しかし、range-based for文の考え方はもっとシンプルです。「カゴの中にあるリンゴを、なくなるまで1個ずつ取り出してシールを貼る」という指示だけで完結します。これが「範囲(レンジ)」に基づいた繰り返しの正体です。
3. range-based for文の基本の書き方
それでは、実際のC++のコードを見てみましょう。まずは数値が入った配列(データの並び)を準備して、その中身を順番に画面に表示するプログラムです。ここでは「コロン(:)」を使うのが最大の特徴です。この記号が「~の中にある各要素について」という意味を持ちます。
#include <iostream>
int main() {
// 5つの数字が入った配列(データの集まり)を用意します
int numbers[] = {10, 20, 30, 40, 50};
// range-based for文の登場です
// 「numbers」という箱の中から1つずつ取り出して「n」という名前に代入します
for (int n : numbers) {
std::cout << n << " "; // 取り出した数字を表示
}
return 0;
}
実行結果は以下のようになります。
10 20 30 40 50
このコードでは、プログラムが勝手に「numbers」の中身が5つあることを理解し、最初から最後まで1回ずつループ(繰り返し)を行ってくれます。int nというのは、一時的にデータを入れておくための変数の名前です。これを変えるだけで、どんな種類のデータでも簡単に扱えます。
4. autoキーワードを使ったさらに便利な活用術
C++には、データの種類(型)をコンピュータに自動で推測させるauto(オート)という非常に便利な機能があります。範囲ベースfor文とautoを組み合わせることで、さらに記述が楽になります。例えば、小数点を含む数字の集まりや、文字の集まりを扱うときに、一々「これは整数」「これは小数」と指定しなくて済むようになります。
特に初心者の方は「どのデータ型を使えばいいかわからない」と悩むことが多いですが、autoを使えばその悩みを解消できます。Google検索で「C++ ループ 効率化」と調べるプログラマーの多くも、このautoと範囲ベースfor文の組み合わせを愛用しています。
#include <iostream>
#include <vector>
#include <string>
int main() {
// 文字列(言葉)のリストを用意
std::vector<std::string> fruits = {"リンゴ", "バナナ", "オレンジ"};
// autoを使うと、中身が文字列であることを自動で判別してくれます
for (auto f : fruits) {
std::cout << "フルーツの名前: " << f << std::endl;
}
return 0;
}
実行結果は以下のようになります。
フルーツの名前: リンゴ
フルーツの名前: バナナ
フルーツの名前: オレンジ
5. 参照(&)を使ってデータを効率よく扱う方法
少し発展的な内容ですが、非常に重要な「参照(リファレンス)」についても触れておきましょう。これまでの例では、カゴからリンゴを「コピー」して別の場所に置いてから作業をしていました。しかし、大きなデータになると、いちいちコピーを作るのはコンピュータにとって負担(メモリの無駄遣い)になります。
そこで、データの名前の前に&を付けることで、「コピーを作らずに、元のデータそのものを指し示す」ことができます。これを「参照」と呼びます。また、元のデータを誤って書き換えたくない場合はconstを組み合わせて使います。これは「読み取り専用」という意味です。パフォーマンスを意識したC++らしい書き方です。
#include <iostream>
#include <vector>
int main() {
std::vector<int> scores = {85, 92, 78};
// const auto& と書くことで、コピーを作らず安全に(書き換え不可で)読み取ります
for (const auto& s : scores) {
std::cout << "点数: " << s << "点" << std::endl;
}
return 0;
}
プログラミング未経験の方は、まずは「const auto&と書くのが、一番エラーが起きにくくて処理も速い魔法の呪文」だと覚えておくだけでも十分です。
6. 範囲ベースfor文で配列の値を書き換える
今までは画面に表示するだけでしたが、範囲ベースfor文を使って、配列の中身を直接書き換えることも可能です。この場合は先ほどの「参照(&)」を使いますが、constは付けません。例えば、テストの点数すべてに5点のボーナスを加点する、といった処理が簡単に書けます。
「一つずつ順番に取り出して、その中身に5を足す」という動作を、全自動で行えるのがこの構文の強みです。もし従来のfor文であれば、scores[i] = scores[i] + 5;といった複雑な書き方が必要でしたが、範囲ベースfor文なら直感的な算数のように記述できます。
#include <iostream>
#include <vector>
int main() {
std::vector<int> data = {1, 2, 3, 4, 5};
// 参照(&)を使って、中身を直接2倍にします
for (auto& val : data) {
val *= 2; // 各要素を2倍にする
}
// 書き換わったか確認
for (int val : data) {
std::cout << val << " ";
}
return 0;
}
実行結果は以下のようになります。
2 4 6 8 10
7. 文字列(string)を1文字ずつ取り出すテクニック
範囲ベースfor文は、数字の配列だけでなく「文字列」にも使えます。文字列は、実は「文字が並んだ列」なので、1文字ずつバラバラにして取り出すことができるのです。例えば、名前を1文字ずつ縦に表示したり、特定の文字が含まれているかチェックしたりするときに役立ちます。
パソコンを触ったことがない方にとって、「こんにちは」という言葉が「こ」「ん」「に」「ち」「は」という5つの部品から成り立っていると考えるのは、プログラミング的思考の第一歩です。C++では、こうした文字列操作も範囲ベースfor文一つで非常にスマートに実装できます。SEOキーワードとしても「C++ 文字列 ループ」はよく調べられるトピックです。
#include <iostream>
#include <string>
int main() {
std::string message = "HELLO";
// 文字列から1文字(char型)ずつ取り出します
for (char c : message) {
std::cout << "[" << c << "]" << std::endl;
}
return 0;
}
[H]
[E]
[L]
[L]
[O]
8. 従来のfor文と範囲ベースfor文の使い分け
ここまで非常に便利な範囲ベースfor文を解説してきましたが、「じゃあ昔の書き方はもういらないの?」と思うかもしれません。結論から言うと、使い分けが大切です。範囲ベースfor文は「全部の要素を順番に処理する」ときには最強ですが、「3番目から7番目までだけ処理したい」とか「1つ飛ばしで処理したい」といった細かい制御には向いていません。
しかし、現代のプログラミングでは、データの全体を安全に扱うことの方が圧倒的に多いため、まずはこの範囲ベースfor文をメインに使い、どうしても細かい指定が必要なときだけ古い書き方(カウンタ変数を使ったfor文)を使うのが、賢いプログラマーへの近道です。この「適切な道具選び」こそが、初心者から中級者へステップアップするための重要なポイントとなります。
9. 範囲ベースfor文を使うときの注意点とコツ
最後に、よくある間違いについても触れておきましょう。範囲ベースfor文を使っている最中に、そのデータの集まり自体のサイズを変える(要素を追加したり削除したりする)ことは原則として禁止されています。これは、カゴの中身を数えている最中に、外から誰かがリンゴを増やしたり減らしたりすると、どこまで数えたか分からなくなってしまうのと同じ理由です。
もしデータを削除したい場合は、別の方法を使う必要があります。しかし、単にデータを読み取ったり、値を更新したりする分にはこれ以上ないほど強力な味方です。C++11以降、そしてC++14、C++17とバージョンが上がるごとに、この構文はより洗練されてきました。最新のC++の機能を使いこなして、美しく効率的なコードを書けるようになりましょう!