[繰り返し(反復)構造と無限ループとbreakとcontinue]

繰り返し構造の基本は、だいたいできたと思います。あとはいろんな例題をこなすうちに自由自在に繰り返しを使いこなせると思います。繰り返しであと詰まりそうなところに、多重ループと無限ループがありそうな気がします。多重ループは、のちに出てくる配列のところに委ねることにして、ここでは無限ループを扱ってみます。

無限ループ

無限ループは、継続条件を常にtrueになる条件にしておいて、絶対に抜けないループを作ることです。

例)

//while文では、継続条件をtrueにすると無限ループを書ける
//前にやったけど、trueは1で表されるので、while(1)でもいいよ
while(true)
{
    命令文;
}
//for(初期値; 継続条件; 再初期化式)の継続条件の部分を省略すると無限ループになる
//for(;;)のように全て省略することが多い 
for(;;)
{
    命令文;
}

//for(;true;) のように、継続条件常にtrueでも無限ループ
for(;true;)
{
    命令文;
}

無限ループは、無限にループから抜けないとてもバグ的な危険な処理の記述であることを覚えておいてください。無限ループを止めるには、だいたいのシステムでは Ctrl + C を押すと止まる(はずである)

ここで新しい用語を覚えてほしい。 何個か前の問題で、C言語では基本的に1つの命令文しか実行できないという話をした気がする。 if文、for文、while文、関数などたいていの場合に、<html><u></html>その構文につづく1つの文しか“基本的に”実行できない<html></u></html>。この1行の単位を単文という。単文は必ず ; セミコロンで終わる。

2つ以上の命令文を続けたいときは{ }でくくりその間に命令文を書く。 <html><u></html>{ }でくくられた複数の単文を複文<html></u></html>という。

int i; //単文
 
{                                            //{-------ここから---------------
    int a = 1, b = 2, c;//これと            
    c = a + b;          //これを合わせて複文  
}                                         //}--------ここまでがブロック-------    

ほんで、この{}で囲まれた範囲をブロックという。

例)forブロック

for(int i=0;i<10;i++)    // for文のための
{                        // ブロックなので
    cout << i+1 << endl; // forブロックとか
}                        // 言ったりする

例)whileブロック

while(true)                          // while文のための
{                                    // ブロックなので
    cout << "Infinite Loop" << endl; // whileブロック
}                                    // とか言う

すなわち、for文とかwhile文は、次に続くブロックをまるっと繰り返す構文であると言える。

breakとcontinue

break命令

ここで、ある条件が成立したら無限ループを抜けることを考えてみる。(そしたら無限じゃないんだけどね) 無限ループ中に、繰り返しブロック内で処理を進めて、ある条件が成立したらループを止めるには、break命令を使う。breakが読み込まれると、それ以降の処理は行わず、breakが現れた時点で、ループが止まります。

例)whileループ

int i = 0;
while(true)
{
    cout << i << " ";
    if(i == 5)
    {
        break;
    }
    i++;
}

実行結果

0 1 2 3 4 5

例)forループ

for(int i = 0; true; i++)
{
    cout << i << " ";
    if(i == 5)
    {
        break;
    }
}

実行結果

0 1 2 3 4 5

whileループもforループも条件( i == 5 ) を満たしたときに、条件分岐によりループが停止されているのが確認できます。

continue命令

break文は、呼ばれたときにその時にbreak文が存在する繰り返しブロックから抜ける命令だったと思います。ループを使ったプログラムを作っているとある条件の時だけ処理をスルーしたい時が結構あったりなかったりします。

以下のソースコードを見てみます。

例)whileループで1~10を表示

int main() {
    int i = 0;
    while(true)
    {
        i++;
        cout << i << " ";
        if(i == 10)
        {
            break;
        }
    }
}

実行結果

1 2 3 4 5 6 7 8 9 10

初めに i を 0 で初期化し、ループの初めにインクリメントして i が 1 ~ 10 までを表示しています。 この時に5未満の時は表示しないという処理を加えてみたいと思います。

例)whileループで5未満の処理を飛ばす

int main() {
    int i = 0;
    while(true)
    {
        i++;
        //--------------------ここから
        if(i < 5)
        {
            continue;
        }
        //--------------------ここを追加
        cout << i << " ";
        if(i == 10)
        {
            break;
        }   
    }
}

実行結果

5 6 7 8 9 10

if文で i が5未満の時にcontinue文を呼んでいます。continue文には次のようなわかりにくい効果があります。

continue;
が呼び出されると、その時の繰り返しブロックの終わり(大体の場合 } 、一行の場合はその行の終わり)まで処理位置がジャンプする。

これを踏まえてもう一度プログラムを見てみます。

int main() {
    int i = 0;
    while(true)
    {//<----------------------繰り返しブロック開始位置
        i++;
        if(i < 5)
        {
            continue; //<- これが呼ばれると------------------
        }                                                  //↓       
        cout << i << " ";                                  //↓   
        if(i == 10)                                        //↓
        {                                                  //↓
            break;                                         //↓
        }                                                  //↓
    }//<----------------------繰り返しブロック終了位置  ←ここにジャンプ
}

ジャンプの間にある行は、単純に読み飛ばされますので実行されません。 breakとcontinueをうまく使うことで、複雑なループ制御を行うことができます。 ただし、多用するとかなり自分以外に理解不能なループを書いてしまうことがあります。また逆に、これらを使うことで、記述を単純化できることもあります。 大体の処理の場合breakとcontinueを使わなくてもかけるパターンに変換できることが多いので、使うときはどの記述が一番他人に見せた時にわかりやすいアルゴリズム記述になるか考えて書くようにしましょう。

最後に同じループをfor文で書いてみます。こっちの方が読みやすいよね(笑)

例)forループで5未満の処理を飛ばす

for(int i = 0; true; i++)
{
    if(i < 5)
    {
        continue;
    }
    cout << i << " ";
    if(i == 10)
    {
        break;
    }   
}

実行結果は同じになります。