繰り返し構文(for文)

    2012/05/22

    本章では下記の内容を学習します。

    • 指定回数繰り返す: for
    • カウンタの調整: 初期設定式・再設定式の変更
    • for 文の中に for 文: ネスト(入れ子)
    • 繰り返しを抜ける: break, continue

    for 文による繰り返し構文

    for 文の基本

    例1-for文による繰り返し
    #include <stdio.h>
    
    int main()
    {
      // 例1: for文による繰り返し
      for( int i=0; i<10; i++ )
      {
        printf( "%d回目の繰り返し\n", i );
      }
    
      return  0;
    }
    

    前回は繰り返し構文として、while文を学習しました。while 文では一定条件のもと繰り返すという条件式を構築していましたが、より単純に『n 回繰り返す』という処理を行いたい場合もあるでしょう。

    for文は、n 回繰り返すという処理を記述するのに適した繰り返し構文です。for 文の ( ) には 3 つの要素を記述することになっており、これが上手く作用して n 回の繰り返しを実現しています;

    1. 初期設定式: 繰り返し回数をカウントする、カウンタ変数を宣言し初期化します
    2. 継続条件式: 何回繰り返したいかを記述します
    3. 再設定式:  繰り返しカウンタ変数を増やしたりします

    例では、10 回繰り返すための記述がなされています。左から順にみていくと、『int i=0;』によって、カウンタ変数 i を宣言し初期化しています。真ん中『i<10;』によって、i が 10 になるまでは繰り返しを行うことを決定しています。右の『i++;』によって、繰り返しごとに i を 1 増やしています。まとめると、最初に i を 0 にして、繰り返しごとに+1 し、10 になったらやめる、となります。

    実行結果を見ると、0 回目~ 9 回目と表示されて終了しています。i は 0 からスタートし、9 まで増やされて、10 になったときに終了しているので、そのような表示になります。プログラムの世界では 0 から数え始めて、n-1 で数え終えるというスタイルのほうが圧倒的に多いので、その数え方に慣れてください。

    練習問題: 繰り返し回数の設定
    1. 繰り返し回数を 25 回に調整してください
    2. 1 ~ 10 までの合計を求めるプログラムを作成してください

    初期設定式・再設定式の変更

    例2-初期設定式などを変更
    #include <stdio.h>
    
    int main()
    {
      // 例2: 初期設定式などを変更
      for( int choco=21; choco>=0; choco-=3 )
      {
        printf( "チョコの残りは%d個、3個食べよう!\n", choco );
      }
    
      printf( "チョコなくなった…\n" );
      return  0;
    }
    

    for 文の ( ) 内は、かならず int i=0; i<N; i++ である必要はありません。変数名を変更したり、初期設定・条件式・再設定式などを変えることができます。

    例では 21 個のチョコを持っていて、3 つずつ食べていくシミュレーションをしています。初期設定式が int choco=21; となり、最初にチョコを 21 個持っていることを表しました。継続条件式はchoco>=0; で、チョコがあれば食べます。再設定式は choco-=3; であり、チョコを 3 つずつ食べていくことを示しています。

    ここでは、for 文の細かい挙動までじっくり解説しましょう。

    1. for 文は最初に実行されたとき、初期設定式を 1 回だけ実行します。ここでチョコが 21 個と定められます
    2. for 文は while 文と同様、条件式をループの開始時にもチェックします。ここは『チョコが 0 個以上あれば OK』という式ですから、21 個あれば十分です
    3. { } ブロック内を実行します。printf 関数で保持個数と、食べたい個数を表示します
    4. { } ブロックが終了しました。このとき再設定式を実行します。チョコは 3 個減ります。残りは 18 個になりました
    5. その後、条件式をチェックします。チョコはまだ 18 個あります、大丈夫です。条件が成立していますので、 { } ブロックを再び実行します
    6. { } ブロックが終了したら、また再設定式が実行されます。チョコは 15 個に
    7. これをひたすら繰り返すと、チョコがちょうど 0 個になります
    8. チョコが 0 個になっても、条件式としては、チョコが 0 個以上あれば OK なので、まだ成立します
    9. { } ブロックを実行します。チョコ 0 個になりましたが、食べたいと表示
    10. { } ブロックが終了し、再設定式が実行されます。ここでチョコの個数は-3 個になります
    11. チョコの個数が 0 を下回りました。条件式が満たされませんので、for 文は終了です

    for 文は、条件が満たされなくなったら終了しますので、このシミュレータは一瞬だけ、チョコの個数がマイナスになってしまいます。一般的に for 文のカウンタ変数は、一回分余分に計算されると考えておいたほうがよいでしょう。もしカウンタ変数を使って別の処理をしたい場合は、注意しておいてください。

    練習問題: マイナス値にならないように変更
    1. 3 個食べられないときは、食べないように変更してください

    break 文

    例3-break
    #include <stdio.h>
    
    int main()
    {
      for( int choco=21; choco>=0; choco-=3 )
      {
        printf( "チョコの残りは%d 個、3 個食べよう!\n", choco );
    
        // break文による強制終了
        if( choco < 10 )
        {
          printf( "食べ過ぎ! 没収!\n" );
          break;
        }
      }
    
      printf( "チョコなくなった…\n" );
      return  0;
    }
    

    while による繰り返し構文では、break 文によって強制終了することができました。for 文も繰り返し構文の一種なので、while 文同様に break 文を利用することができます。

    break 文は、for ループの中にあらわれた場合、その段階で即座に for ループを抜け出す命令文です。例ではチョコが 10 個を下回った場合、どこからともなく食べ過ぎという指摘が入り、チョコを没収されてしまいます。

    for 文では、継続条件式にはカウンタ変数のチェックに関する内容を書くことが多いため、そのほかの条件によって強制終了するための break 文が比較的多用されます。繰り返し構文に break 文はなくてはならないものですので、ここで押さえておきましょう。

    練習問題: 食べきるように変更
    1. かわいそうなので、没収はやめてあげてください
    2. そして、チョコが 20 個でも、ちょうど「食べ切れる」ように改造してください(端数だけを食べる)

    continue 文

    例4-continue
    #include <stdio.h>
    
    int main()
    {
      for( int i=1; i<20; i++ )
      {
        // 3 の倍数でなければ continue で処理をスキップする
        if( i%3 != 0 )
        {
          continue;
        }
    
        // 3の倍数のみ、ここに到達する
        printf( "%dは3の倍数\n", i );
      }
    
      return  0;
    }
    

    繰り返し構文の強制抜け出しには、break によるループ全体の強制終了のほかに、そのループのみスキップするという構文があります。

    continue 文は、実行されると、その後ろにある処理をすべてスキップして、チェック式まで戻る命令です。continue が break と異なるのは、break がループ全体を強制抜け出しするのに対して、continue はループを 1 回だけスキップするという考え方です。ですから continue が実行されても、ループそのものを終了することはありません。

    continue は、複数回行われるループのなかで、ある一定の条件のときは処理を行いたくない、といった場面で特に有効です。例では 1 ~ 20 の整数値のうち、3 の倍数に該当するときだけ処理を実行するというプログラミングがなされています。3 の剰余が 0 でなければ、それは 3 で割り切れず、3 の倍数ではないため、continue によってループをスキップしているわけです。

    練習問題: 倍数の表示

    ユーザから整数値を入力してもらい、1 ~ 100 の数値の中で、ユーザ入力値の倍数であるもののみを表示するプログラムを作成してください (7 なら、『7, 14, 21, 28, 35, 42, 49, 56, 63, 70, 77, 84, 91, 98』になる)

    for 文のネスト

    例5-for
    #include <stdio.h>
    
    int main()
    {
      for( int i=0; i<4; i++ )
      {
        printf( "%d 回目の for ループはじまるよ!\n", i );
    
        // for文の中にfor文を入れてもOK
        // ただしカウンタ変数名は変えた方が良い
        for( int j=0; j<3; j++ )
        {
          printf( "内側のfor、%d回目\n", j );
        }
    
        printf( "%d回目のforループおわり\n\n", i );
      }
    
      return  0;
    }
    

    for 文や while 文で繰り返し処理を行う中で、さらに繰り返し処理を行いたい場合はどうすればよいでしょうか?

    for 文や while 文は、何個でも内側に入れることができます。この内側に入れることをネストや入れ子と呼び、1 つネストすると、そのループは 2 重ループや 2 段ループなどと呼称されるようになります。

    例では 2 重ループが構成されており、4 回の外ループと、3 回のうちループで、内側の printf 関数は合計 12 回実行されています。このような 2 重ループが重要となるのは、2 次元的に展開する情報、つまり画像処理や表計算処理などです。実践問題では、これに挑戦してもらいます。

    繰り返し構文は、2 つ 3 つとネストすることも可能です。しかしながらたとえば 10 回の繰り返しを 3 回ネストすれば、10×10×10×10=10,000 回の繰り返しが必要となりますから、多重にネストすることには注意が必要です。多重にネストする必要があるのか、考えてから利用してみてください。

    実践問題: 九九表の作成

    九九表を表示するプログラムを作成します。

    1. a×b=c という形式で、1×1=1 から 9×9=81 までの 81 通りを表示してください
    2. 九九表を表形式で表示することを考えてください