9.制御構文 – ループ

特定の処理を繰り返し実行するのがループです。
ループは何らかの条件を満たすまで処理を繰り返させるため、比較演算子や論理演算を使用して、その結果がtrueかfalseかでループ続行の判断を行います。

ループを書くにはいくつかの方法があります。

for文

for文は、ループさせる回数が分かっている時に使用するループです。

for(初期値; 条件式; 増分){
   ループさせる処理
}

のように書きます。
処理の流れとしては、

  • 初期値を用意
  • 条件式を評価
  • trueならループさせる処理を実行
  • 増分を処理
  • 条件式を評価
  • trueならループさせる処理を実行
  • falseなら終了

となります。

例えば、10回ループさせる場合の処理は、以下のように書きます。

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

初期値として、int i=0
条件式として、i<10
増分として、i++
を書いています。

ちょっとごちゃっとしていますが、

  • int型の変数iを用意し、0を代入
  • iが10より小さい間はPrint処理でiを表示する
  • iを1増やす

という処理になります。
実行すると、

0
1
2
3
4
5
6
7
8
9

と表示されます。

初期値として用意するint型の変数名が「i」なのは慣例的なもので、こうしなければならないわけではありません。
「i」なのは、indexの頭文字だと思われます。

また、初期値が1ではなく0なのにも理由があります。
配列の章で触れたように、ループ処理は配列と相性が良いです。
10個の配列を順番に処理するといった場合、配列のインデックスは0から始まるので、変数iを配列のインデックスとして利用することができます。

double numbers[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for(int i=0; i<10; i++){
   Print(numbers[i]);
}

変数iに代入されている値は0から9まで増えるので、このように書くとnumbers[0]からnumbers[9]までを順番に処理することができます。

また上記では配列の要素数が10であることが分かっているので、ループの条件式をi<10としていますが、この”10”はマジックナンバーです。
配列の要素数が変更されればここも書き換える必要があり、あまりスマートな書き方ではありません。

配列の要素の数だけループさせたい場合は、ArraySizeという関数を使用することが推奨されます。

double numbers[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for(int i=0; i<ArraySize(numbers); i++){
   Print(numbers[i]);
}

ArraySize(numbers)で、配列numbersの要素数を取得しています。
このように書けば、配列の要素数がいくつであろうとその分だけループ処理が行われるようになります。
突然出てきた「関数」については、次章で解説します。

また、初期値・条件式・増分をひっくり返すことで、配列を逆から順に処理することもできます。

double numbers[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for(int i=ArraySize(numbers)-1; i>=0; i--){
   Print(numbers[i]);
}

このように書くと、

  • 初期値は、配列numbersの要素数-1(要素数が10なら9が初期値になる)
  • 条件式は、iが0以上の時(iが-1になったらループを抜ける)
  • 増分は、iを1ずつ減らす

となり、numbers[9]からnumbers[0]までを順番に処理することができます。

また、ループ処理内にループ処理を記述するケースがあります。
10回ループの中に10回ループを書く場合、外側のループをA、内側のループをBとすると、

  • Aの1回目でBが10回ループ
  • Aの2回目でBが10回ループ
  • Aの10回目でBが10回ループ

となります。

例えば、

for(int i=1; i<10; i++) {
   for(int j=1; j<10; j++) {
      Print(i * j);
   }
}

このように書くと、かけ算の九九のような表示になります(1の段~9の段までの数字が順番に表示される)。

while文

while文は、ループさせる回数が不明な場合に使用するループです。

while(条件式){
   ループさせる処理
}

のように書きます。
条件式が満たされている間、ループさせる処理が繰り返し実行されます。

for文のように初期値や増分が書かれていませんが、少なくともいつかは条件式が満たされる必要があります。
前述のfor文のループをwhile文で書くなら、以下のようになります。

double numbers[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int i=0;
while(i<ArraySize(numbers)){
   Print(numbers[i]);
   i++;
}

処理結果は全く一緒になります。
実際、どちらのループを使っても表現できないという事はありません。
なので、どちらを使っても構わないのですが、ケースバイケースでどちらが書きやすいかが変わります。

もう少しwhile文の例を挙げておきます。
除算演算子を使わず、ループと引き算を使って、割り算500/7の答えを求めてみます。

int number = 500;
int count = 0;
while(number >= 7){
   number -= 7;
   count++;
}
Print(count);

変数numberから7を引き続けて、その回数を変数countでカウントしています。
これを変数numberが7未満になるまで繰り返し、ループが終わった後の変数countには、割り算500/7の答えが代入されています。

while()の部分に記述する条件式が特に無い場合は、以下のように記述するケースもあります。

while(true){
   ループさせる処理
}

条件式にtrueとだけ書いた場合、常に条件が満たされていることになり、無限ループになります。
無限ループは、本当に無限に終わらないので、プログラムがこのループに入った時点で見た目上プログラムは停止します(MT4/5は応答なしの状態になります)。

このような無限ループを抜けさせるには、条件分岐のswitch文でも使用したbreakを使います。

while(true){
   ループさせる処理
   if(条件式){
      break;
   }
}

このように、ループさせる処理の中に別の条件式を仕込み、その条件が満たされた場合にbreakするようにします。
breakが実行されるとそこでループが終了します。

ちなみにbreakはfor文の中でも使用することができます。

条件が複雑になってくると、正しくループしてくれるのかどうか、パッと見では判断しにくくなることがあります。
特に無限ループに陥ると、MT4/5を強制終了する羽目になったりするので、非常に面倒です。

このように少し注意点はありますが、ループは非常に強力な制御構文ですし、うまく使えばコーディングがとても楽になります。
ループ続行・終了の条件がどのように変化していくかをしっかり確認し、ループをマスターしましょう。

以上がループです。

次回は、ブロックとスコープについて解説します。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

コメントする