くりかえし処理

前回扱った条件分岐とあわせて、実際のプログラミングに欠かせないのが、処理をくりかえす方法です。 今回は、実際に繰り返し処理を行うための「 while 文 」と「 for 文 」を使ってみましょう。

実用的なくりかえし処理では、ただ処理をくりかえすだけでなく、 カウンタの値などを毎回書き変えたり、その結果に応じてくりかえしを終了したりもします(そうしないと無限ループになってしまいます)。 これは意外と処理の流れが複雑になり、つまづきやすいポイントでもあります。 そこで今回も、前回登場したフローチャート を用いて、処理の流れを絵で表しながら解説していきます。

- 目次 -

くりかえし処理の基本となる、2つのパターン

一言で「 くりかえし処理 」といっても、そのパターンは一通りではありません。 たとえば、もしあなたが「 この作業をくりかえしてください 」 と だけ 指示されても、 「 一体いつまで…? 」 と困ってしまいますよね。

くりかえしには条件が必要という例の図

そう、実用的なくりかえし処理には、ふつう 「 いつまでくりかえすのか 」 という指示もいっしょに必要になります。 この指示は、たとえば以下のようなパターンが考えられます:

たとえば「 ストップと言われていない間はくりかえす 」は (1)、「 10回くりかえす 」は (2) にあたります。 もっと別のパターンも考えられますが、この2つはプログラミングにおいて特に基本となるので、必ず押さえておきたいものです。

それでは、実際にくりかえし処理を行ってみましょう。

条件が成り立っている間だけ処理をくりかえす

while 文( ホワイルぶん )

まずは、「 条件が成り立っている間 」 だけ処理をくりかえす方法についてです。 これには、 「 while 文 ( ホワイルぶん ) 」 というものを使用します。 while 文は、前回扱った条件分岐の if 文とよく似ています。 特に書き方は以下の例の通り、 if の代わりに while と書くだけです:

// 整数の変数「 x 」を宣言し、最初に値「 1 」を代入
int x = 1;

// 条件 x == 1 が成り立つ間だけくりかえされる( == は等号)
while ( x == 1 ) {

     // くりかえし処理の中で、毎回メッセージを表示
     println ( "while文実行中" ) ;

     // x の値を、ユーザーに入力してもらう
     x = input ( "数字を入力してください" ) ;
}


// くりかえし処理が終わったら、最後にメッセージを表示
println ( "くりかえし終了" ) ;

内容の説明はすぐ後でするとして、とりあえず実行してみましょう。 このプログラムを実行すると、以下のようにまず画面に「 while文実行中 」と書かれて、続いて値を入力するウィンドウが表示されます。

while文のサンプル実行結果の図

ここで入力ウィンドウに「 1 」と答えると、また画面に「 while文実行中 」と追記され、再び入力ウィンドウが表示されます。 「 1 」と答えている間は、ずっと同じ事がくりかえされ続けます。 逆に「 1 」以外の数字を入力すると、「 くりかえし終了 」というメッセージが書かれて終わります。 ちゃんと、くりかえし処理になっていますね。

さて、プログラム内容の説明です。「 while 」の部分に注目してください。 そのあとの 丸いカッコ ( ... ) の中には、if 文と同じように、条件式を書きます。 上の例での条件式 ( x == 1 ) は、「 x の値が 1 と等しければ 」という意味です。イコール記号「 = 」は、1個ではなく2個続いている事に注意しましょう。 if 文の場合は、ここに書いた条件が成り立っている場合だけ、 波っぽいカッコ { ... } の中の処理が実行されるのでしたね。この事は、while 文でもまったく同じです。

while文の構文の説明図

ただし if 文では、{ ... } の中の処理は、1 回だけ実行されて終わりでした。 それに対して while 文では、 { ... } の中の処理が終わったタイミングで、 処理はまた「 while 」と書かれているところまで戻ってきます。 そして、条件が成り立っているかどうかが再び確認されます。 もし成り立っていれば、 また { ... } の中の処理が実行されます。これがくりかえされます。 逆に、条件が成り立っていなければ、{ ... } の中は実行されず、処理はもう「 while 」のところにも戻りません。 くりかえし処理はもう終わりで、ふつうにその下の処理が実行されていきます。

文章だけで説明するのもややこしいですね。そこで上のプログラムにおける処理の流れを、 前回登場したフローチャートにしてみると、以下のようになります:

while文のフローチャートの図

上のフローチャートの真ん中〜左にかけて、「 わっか 」のように一周回って閉じている部分が、くりかえし処理の部分になっています。 条件の判断はひし形の部分で行われ、条件が成り立っている間は YES の矢印のほうに処理が流れて、 このわっか( ループ )をぐるぐると回り続ける 事になります。確かにくりかえしですね。 そして条件が成り立たなくなれば、処理はわっかを「 脱出 」して NO の矢印へ進み、くりかえし終了です。

上のフローチャートを見ながら処理を追いかけると、 確かにユーザーが「 1 」を入力し続けている間は、処理がくりかえされますね。 もう一度プログラムを実行し、見比べてみてください。

くりかえしを途中で終わらせる 「 break 文( ブレイクぶん ) 」

上の例では、くりかえしを続けるか終わるかを、while 文やのカッコ内に条件式として書きました。 でも、その条件式とは無関係に、強制的にくりかえしを終わらせる方法も存在します。 それが break 文( ブレイクぶん )です。 break 文の使い方は単純で、プログラム内で「 break 」と書くだけで、その行が実行された時点でくりかえしが終了します。

( ※ くりかえしが何重にもなっている場合は、一番内側のくりかえしが終了します。)

試してみましょう。 これまでは説明しませんでしたが、実は条件式に「 true 」と書くと、「 常に成り立つ条件 」になります。 つまり while ( true ) { ... } と書けば、いつまでもくりかえされる処理になります。 これを break 文で終わらせてみましょう:

// くりかえしの条件が常に成り立つ処理
while ( true ) {

     // くりかえし処理の中で、毎回メッセージを表示
     println ( "くりかえし中" ) ;

     // 変数 x を宣言し、値をユーザーに入力してもらう
     int x = input ( "数字を入力してください" ) ;

     // もし x の値が 1 以外なら、くりかえしを終わる
     if ( x != 1 ) {
         break ;
     }
}

// くりかえし処理が終わったら、最後にメッセージを表示
println ( "くりかえし終了" ) ;

if 文の中で使っている ( i != 1 ) は、「 i が 1 以外の場合 」という条件です。 この条件が成り立つ場合に、if 文の { ... } 内に書かれた break 文が実行され、くりかえしが終わるというわけです。 このプログラムの実行結果は、先ほどの例とまったく同じです。 「 x が 1 の間だけくりかえす 」という事と、「 x が 1 でなければくりかえしを終わる 」という事は同じだからです。

決まった回数だけ処理をくりかえす

回数が決まったくりかえしには、「 カウンタ変数 」で回数を数えれば OK!

続いて、「 決まった回数 」 だけ処理をくりかえす方法についてです。 実はこれは、条件が成り立っている間のくりかえしを使って実現できます。 つまり、すでに扱った while 文でもできるのです。 具体的には、回数を数えるための変数を用意して、以下のように使います。 この変数は一般に 「 カウンタ変数 」 と呼ばれます。

文章だけだと分かりづらいので、フローチャートにしてみましょう。以下の通りです:

カウンタ変数を用いた回数くりかえしのフローチャートの図

実際にノートなどに、カウンタ変数の値を書きかえながら、上のフローチャートの処理をなぞってみてください。 決まった回数だけくりかえされる仕組みのイメージがつかめると思います。

まずは、while 文を使って行ってみる

上のフローチャートに書いた処理は、すでに扱った while 文でも実現できます。 ちょうどいい練習にもなるので、まずは while 文で行ってみましょう。プログラムは以下の通りです:

// 整数型のカウンタ変数 「 i 」を宣言し、値「 0 」を代入
int i = 0 ;

// カウンタ変数が 10 未満( 10 は含まない)の間くりかえす
while ( i < 10 ) {

     // くりかえし処理の中で、毎回カウンタ変数の値を表示
     println ( i ) ;

     // 毎回のくりかえしの最後に、カウンタ変数に 1 を加算
     i = i + 1 ;
}


// くりかえし処理が終わったら、最後にメッセージを表示
println ( "くりかえし終了" ) ;

このプログラムの実行結果は、以下の通りです:

0
1
2
3
4
5
6
7
8
9
くりかえし終了

この通り処理がくりかえされ、その間、毎回カウンタ変数の値が表示されています。 表示されているのは「 0 」から始まって「 9 」で終わっているので、ちょうど 10 回くりかえされた事がわかりますね。 このようにカウンタ変数の値が「 0 」からスタートする場合、 くりかえしの最後でのカウンタ変数の値は、「 くりかえし回数 - 1 」 になる事に、 慣れるまで注意が必要です。

最後のくりかえしでのカウンタ変数の値は「 くりかえし回数 」に一致するほうが、すっきりするかもしれません。 その場合はカウンタ変数を値「 1 」からスタートさせて、 while 文の条件で 「 i <= 10 」 のように「 <= 」記号を使えば OK です。 でも、くりかえし処理は配列と組み合わせて使う事が多く、 配列の要素のカウントも「 0 」から「 要素数 - 1 」までなので、 くりかえしも 0 からスタートする方が、処理で好都合な場合が多いです。ぜひ慣れましょう。

こういう場合には for 文( フォーぶん )を使うと便利!

さて、上のように決まった回数のくりかえし処理を while 文で行うと、 カウンタ変数の宣言と加算のために、プログラム内で 2 行使う必要があります。 でも、決まった回数のくりかえし処理は非常によく使うので、できればもっと短くまとめたいところです。

また、別の人がプログラムを読んで、くりかえし処理の流れを追いかける際など、 カウンタ変数のスタートの値や加算処理は、くりかえしの条件とワンセットで把握する必要があります。 場合によっては、カウンタ変数が中途半端な値からスタートしたり、毎回加算する数が 1 ではない場合もよくあるからです。 その点でも、これらの処理は一か所にまとめたいところです。

そこで便利なのが 「 for 文( フォーぶん )」 です。 for 文なら、これらを 1 つにまとめて書くことができます。 先ほどの while 文を使ったプログラムと全く同じ処理を、for 文を使って書きなおすと、以下のようになります:

// カウンタ変数「 i 」が 10 未満( 10 は含まず)の間くりかえす
for ( int i = 0 ; i < 10 ; i = i + 1 ) {

     // くりかえし処理の中で、毎回カウンタ変数の値を表示
     println ( i ) ;
}


// くりかえし処理が終わったら、最後にメッセージを表示
println ( "くりかえし終了" ) ;

ずいぶん短くまとまりましたね。 上のプログラム内で、「 for 」というキーワードで始まっているところが for 文です。 「 for 」のすぐあとのカッコ内は ( ... ; ... ; ... ) の形になっていて、「 ; 」 記号で区切って 3 つの式が書かれてる 事に注目しましょう。 これら 3 つの式は、それぞれ以下のような役割をもっています:

for文の構文の説明図

文章の説明だとなかなか複雑そうですが、フローチャートにすると以下の通りです:

for文のサンプルにおけるフローチャートの図

このようにフロー自体は、普通に while 文でカウンタ変数を使った場合の、一定回数くりかえしの処理と変わりませんね。 ようするに、先ほどの while 文のプログラムで別々に書いていた、カウンタ変数の宣言と加算処理を、for 文だと条件式の両どなりに押し込めて書けるというだけ です。 なので、プログラムの実行結果も以下の通り、先ほどの while 文を使った例とまったく同じになります:

0
1
2
3
4
5
6
7
8
9
くりかえし終了

この通り、確かにまったく同じ結果になりましたね。

for 文と while 文は、どちらでも同じ処理を書けるものの、用途に応じて使い分けると読みやすくなる

実は for 文のカッコ内 ( ... ; ... ; ... ) の左側の式は、必ずしも「カウンタ変数の初期化処理を書かなければいけない」というわけではありません。 同様に右側の式も、「 カウンタ変数の更新処理を書かなければいけない 」と決まっているわけではありません。 ルール上は、前者はくりかえしの前、後者は1周ごとに毎回実行する処理であれば、なんでも書く事ができます。 実は左右になにも書かなくても OK で、そうすると while 文と同じ、単なる条件くりかえしの処理になります。

for 文を使ったくりかえし処理は、すべて while 文でも行えますし、逆に while 文と同じくりかえし処理も for 文で行えます。

でも、カウンタ変数の操作のように、くりかえしの条件に関わる「 動き 」を、条件式の両どなりに書けるという事に、for 文を使う一つの利点があるわけです。 程度問題で人にもよりますが、あまりくりかえしの条件と無関係な処理が、for 文のカッコ内に書かれていると、読みづらいと感じる人もいるかもしれません。 読みやすさを考えて、for 文と while 文をうまく使いわけましょう。

くりかえし処理に使うと便利な演算子

さて、ここまで例に使ってきたプログラムの通り、くりかえし処理の中では、「 なにかの変数の値を書きかえる 」という処理がよく登場します。 カウンタ変数の加算などはいい例ですね。 実はこういった処理は、短く書ける便利な演算子( 記号 )がいくつかあります。

インクリメント演算子とデクリメント演算子

たとえば、これまでの例ではカウンタ変数「 i 」に 1 を加算するのに、「 i = i + 1 」と書いてきました。 これは、足し算の記号である「 + 」演算子と、代入の記号である「 = 」演算子を組み合わせて、「 いまの『 i 』の値に 1 をたして、その結果で『 i 』を書きかえる 」 という処理を実現していたわけです。

でも、実はこれと同じ処理は、足し算の記号を 2 個並べた「 ++ 」という演算子だけで行えます。 これはインクリメント演算子と呼ばれ、「 ++ i 」や 「 i ++ 」のように、変数の前や後に書いて使います。 前後のどちらに書くかは、式の中にめり込ませて使った場合に違いが出るのですが、単体で使う場合はどちらも 「 i = i + 1 」 と同じ結果になります。使ってみましょう:

// カウンタ変数「 i 」が 10 未満( 10 は含まず)の間くりかえす
for ( int i = 0 ; i < 10 ; i ++ ) {

     // くりかえし処理の中で、毎回カウンタ変数の値を表示
     println ( i ) ;
}

// くりかえし処理が終わったら、最後にメッセージを表示
println ( "くりかえし終了" ) ;

for 文のカッコ内が、より短くまとまりましたね。実行結果はこれまでの例と同じです:

0
1
2
3
4
5
6
7
8
9
くりかえし終了

このようにカウンタ変数を 1 ずつ加算する for 文では、インクリメント演算子を使って書くのが一般的です。

なお、インクリメント演算子の逆バージョンとして、変数を 1 だけ少ない値で書きかえる、つまり「 i = i - 1 」と同じ処理を行う「 -- ( マイナス記号が2個連続 )」という演算子もあります。 それはデクリメント演算子と呼ばれ、「 i -- 」のように書いて使います。これもくりかえし処理の中でよく用いられます。

「 2 ずつ加算したい場合 」などに便利な、複合代入演算子

インクリメント演算子では、変数の値を 1 しか加算できないですが、1 以外の値だけ加算したい場合もよくあります。 たとえば、for 文のカウンタ変数を 2 ずつ加算したい場合などです。 このような場合、for 文のカッコ内の右の式に、そのまま「 i = i + 2 」と書いてもいいのですが、そのかわりに「 i += 2 」と書いても OK です。試してみましょう:

// カウンタ変数「 i 」が 10 未満( 10 は含まず)の間くりかえす
// ただし、カウンタ変数は 2 ずつ加算する
for ( int i = 0 ; i < 10 ; i += 2 ) {

     // くりかえし処理の中で、毎回カウンタ変数の値を表示
     println ( i ) ;
}

// くりかえし処理が終わったら、最後にメッセージを表示
println ( "くりかえし終了" ) ;

実行結果は以下の通りです:

0
2
4
6
8
くりかえし終了

ちゃんとカウンタ変数が 2 ずつ増えていますね。

このように、演算の記号(足し算や引き算などの記号)に「 = 」を続けて書くと、 左辺の変数の値を、右辺の値で足したり引いたりした演算結果で書きかえる事ができます。 かけ算や割り算でも使えます。 なお、この「 += 」のような記号は複合代入演算子と呼ばれます。