今回は、処理を場合によって分ける「 条件分岐 」の概念、およびそのために用いる「 if 文 」というものを扱います。
条件分岐および if 文は、様々な言語でのプログラミングにおいて日常的に用いる、とても重要な要素です。 一方で、複数組み合わせると処理の流れが複雑になり、混乱しやすいポイントでもあります。
そのためここでは、多少内容がくどいかもしれませんが、処理の流れを絵で表す「フローチャート」などを用いて、一歩一歩足場を固めながら解説していきます。 if 文の場所で処理の流れが「 枝分かれ 」していくイメージを、ぜひマスターしましょう。
これまでの例では、プログラムに書いた処理内容が、すべて実行されてきました。 でも、実際に色々な作業を自動化しようと思うと、そのプログラム内には、 「 状況に応じて処理を行ったり、逆に行わなかったり、または別の処理を行ってほしい 」 という部分もでてきます。
単純な例として、「 もし変数 x (エックス)の値がマイナスなら、ゼロにしたい 」 という場面を考えてみてください。実際のプログラム内で、こういう状況はよくあります。 こういう場合は、プログラムをどのように書けばよいでしょうか?
たとえば、まずは直球でそのまま、以下のように書くのはどうでしょうか。
最後の部分は、実用的なプログラムでは x を使って計算などの処理を行うのでしょうが、 ここではあくまでも簡単な例なので、 x の値を表示するだけにしています。
さて上のプログラムでは、x の値がマイナスになっているところで、素直に x の値をゼロにする処理 「 x = 0 ; 」 を書いています。実際に実行してみると:
この通り、あたりまえですが、0 が表示されます。 コンピューターにとっては、確かにマイナスだった x の値をゼロにしたわけなので、目的通りの事をやっています。 ある意味で一つの正解かもしれません。x がマイナスの状況に限っては。
でも、上のプログラムでは、x の値をプラスの値に書きかえても、 常に「 x = 0 ; 」の行のところで 0 にされてしまいます。 それはまずいですね。あくまでも「 マイナスの場合はゼロにしたい 」というだけなので、 そうでない場合には、ゼロにしてはいけません。
強引な方法ですが、確かに実行すると x の値がそのまま変化せず
と表示されます。 まあ、これも x がプラスの状況に限っては、間違いではない…かもしれません。 でもこういう解決法だと、 x の値が変わるたびに、 一緒に「 x = 0 ; 」の行も付けたり消したりと、手動で書きかえないといけません。 それはちょっと面倒ですね。うっかり作業ミスが入り込む危険性もあります。
という事で、上の例での「 x をゼロにする処理 」のように、 状況に応じて処理を付けたり消したり ( 行ったり行わなかったり ) という事を自動化できると便利ですね。 これを可能にしてくれるのが「 条件分岐 」です。 詳しい説明は後にして、まずは先ほどの例で使ってみましょう:
このとおりです。上のプログラムで、「 if ( x < 0 ) { 」 と、 「 } 」 記号とで囲まれた部分が、条件分岐です。 この条件分岐は if というキーワードではじまるので、if 文( イフぶん )とも呼ばれます。 if というのは英語で「 もし 」という意味で、「 もし 〜 だったら 」の「 もし 」です。
この条件分岐では、if のあとの 丸いカッコ ( ... ) の中に条件を書きます。 そして、その条件が成り立つ場合のみ、波っぽいカッコ { ... } の中の処理が実行されます。 処理は複数行でもかまいません。
条件が成り立たない場合、 { ... } の中の処理はすべて無視されます。 なお、{ ... } の中身を微妙に右にずらして書いてあるのは、単純に読みやすさのための慣習で、動作には関係ありません。 ( ※「 Tab 」キーを押すとずらせます。 )
いろいろな条件の書き方は後で詳しく説明しますが、ここで条件にした ( x < 0 ) は、「 x の値がゼロより小さければ 」という意味で、つまり「 x の値がマイナスだったら 」という意味と同じです。 よって上の例の条件分岐は、 「 もし x の値がマイナスならば、『 x = 0 ; 』の処理を実行する 」 という内容になっているはずです。それでは実行してみましょう:
この通り、確かに上のプログラムでは x の値が「 -100 」つまりマイナスなので、 「 x = 0 ; 」の処理が実行され、その結果 x の値がゼロになった事がわかります。
では x がプラスならどうなるでしょう? 上のプログラムで「 x = -100 ; 」の行からマイナスをとって、「 x = 100 ; 」に書きかえて再実行してみてください。 結果は以下の通りです:
このとおり、x が最初の値のままになりました。 つまり今度は x がマイナスではないので、条件分岐の条件 x < 0 が成り立たずに、「 x = 0 ; 」の処理が無視されたわけです。
以上のように条件分岐を使って、ちゃんと最初の目的 「 もし変数 x の値がマイナスなら、ゼロにしたい 」 という事を自動化できました。
ところで、今回の最初で行ったように、状況に応じて手動でプログラムを書きかえる方法は、そもそも不可能な場合もあります。 というのも、実際の場面では 「 プログラムが実行されるまで、どういう値になるかわからない 」 という状況もよくあるからです。 典型的な例としては、ユーザーに値を入力してもらう場合などがあげられるでしょう。以下のような場合です:
上のプログラムで使っている input 関数 は初めて登場しましたが、これはユーザーに値を入力してもらう関数で、このようにイコール記号(代入演算子)の右側に書きます。 すると左の変数に、ユーザーが入力した値が代入されます。
このプログラムを実行すると、まず入力ウィンドウが表示され、 そこで入力した値が変数 x に代入されます。 その後の処理は、先ほどの例と同じです。 もし入力された x の値がマイナスなら、条件分岐の中の処理が実行され、その結果 x がゼロになって「 0 」と表示されます。 そうでなければ、ユーザーが入力したままの x の値が表示されます。
この例では、 x の値がユーザーの気分次第で変わるので、 プログラムを書いている時点では、その値は全くわかりません。 なので、最初に行ったような、プログラムを手動で書きかえる方法ではどうやっても対応できませんが、 このように条件分岐を使えば対応できます。
ところで、前回までの内容では、プログラムは 1 行ずつ順に実行されるものでした。 つまりプログラムの 処理の「 流れ 」は、「 最初の行から最後の行へ 」つまり 「 上から下へ 」という一本道だったわけです。
しかし今回、プログラムの中で 「 状況に応じて、実行せずに飛ばされる部分 」 というものが出てきました。 その結果、処理の流れはもはや一本道ではなく、以下のように枝(えだ)わかれしたものになってしまいます:
この「 処理の流れの枝わかれ 」というものは、 実はなかなかのクセものです。 ここまでの例のように単純な場合はいいのですが、 実際の場面では、条件分岐の中にさらに条件分岐が必要になったり、 さらにその中にまた条件分岐が入ってしまう場合もあります。 こうなると、処理の流れは網のように枝わかれし、条件も複雑に組み合わさってきます。
一方で、ふつう人間が日常生活を送る上で、同時に想定している状況の数は、多い時でも 3 個くらいですよね。 それに対して、現実的なプログラムの中であり得る「 処理の枝 」や状況の数はもっと多くなるので、慣れないと頭がこんがらがってしまったり、 想定しきれていない条件パターンの「 枝 」が残って、プログラムが想定外の動きをしてしまったりします。バグですね。
そこで、処理の流れを図に描いて整理すると便利です。 その図とは一般に 「 フローチャート 」 と呼ばれるものです。 「 フロー 」とは英語で「 流れ 」という意味です。 実際に先ほどの例で描いてみましょう:
こんな感じです。 ちゃんとしたフローチャートの描き方には、いくつかの規格や種類があるのですが( 枠線や矢印、図形の使い方など)、 そういった細かいルールをプログラミング言語と一緒に覚えるのは大変なので、ここでは思い切り簡略化しています。 描き方はシンプルで、以下の3つのルールに基づいています:
では、上のフローチャートを読んでみましょう。 基本的には「 あみだくじ 」みたいな要領で、上から下に矢印をたどって読んでいきます。 長方形はふつうの処理なので、ふつうに読み進みます。まず変数 x を宣言して、続いて、それにユーザーからの入力値を代入するわけですね。
その後にひし形があります。これは条件分岐で、ひし形の中に条件が書かれています。 ここからの処理の流れは枝分かれし、条件が成り立つ場合は「 YES 」の矢印に、成り立たない場合は「 NO 」の矢印に進みます。 前者の場合には x をゼロにする処理が続きますが、それは後者の場合ではスキップされる( とばされる )事がわかりますね。
その後、枝分かれした処理は合流し、x の値を表示して、プログラム終了です。 どうでしょうか。処理の流れがわかりやすくなった感じがしませんか?
フローチャートを読めるようになったところで、もう少し複雑な条件分岐を使っていきましょう。 条件分岐で、条件が成り立たなかった場合には、別の処理を行いたいという場合もよくあります。 それには以下のように、「 if 文 」の後に 「 else 文( エルスぶん ) 」を書けば OK です:
else 文の { ... } の中に書いた処理は、すぐ上の if 文の条件が成り立たなかった場合にだけ、実行されます。 逆に if 文が条件成立して実行された場合、else 文の中の処理は実行されません。 else は英語で「 そうでなければ 〜 」といった意味で、これは if が「 もし 」という意味だったのと、わかりやすく対応しています。
つまり上のプログラムでは、 「 もし( if )変数 x がマイナスなら 0 を代入し、そうでなければ( else )変数 x に1 を代入する 」 という処理になります。フローチャートは以下の通りです:
条件分岐( ひし形 )の「 NO 」の矢印の先に、x を 1 にする処理が追加されましたね。そこが else 文の部分です。 このプログラムでは、x の値は先と同様、ユーザーの入力値が代入されるようになっています。 実行していろいろな値を入力し、フローチャートと見比べてみましょう。
上の例では、if 文の条件が成り立たなければ、その時点で無条件で else 文の中が実行されます。 でも、この else 文の実行に、さらに条件を設けたいという場合もあります。 そのような場合は以下のように、else 文のあとに if 文をくっつけます:
こうすると、まず最初の if 文が条件不成立の時点で、処理は else 文のところまで進みます。 そこでさらに条件 x < 10 ( x が 10 未満 )が成り立つ場合のみ、その後の { ... } の中の処理が実行されます。 文章だとややこしいですが、フローチャートだと以下の通りです:
やはりフローチャートだと見やすいですね。 これも、実際に実行していろいろな値を入力してみて、フローチャートと見比べてみてください。 この「 else if 」は何個もつなげたり、最後に条件なしの else 文をつなげる事もできます。
なお、if 文を別の if 文や else 文の { ... } の中に入れるなど、入れ子にする事もできます。
さて、最後です。いろいろな場合において、if 文のカッコ内の条件を、どのように書けばよいかを、一通り抑えておきましょう。
ここまで用いてきた「 x < 10 」は、「 x が 10 よりも小さいか? 」という条件でしたね。 この「 < 」は、一般に「 比較演算子 」と呼ばれるものの一つです。名前は難しそうですが、要するに「 比較を行う記号 」です。
比較演算子は、別名として「関係演算子」と呼ばれたりもしますが、 名前が似ていて別種の「条件演算子」と紛らわしいので、ここでは比較演算子と呼びましょう。
比較演算子には、全部で以下のようなものがあります:
どれも、YESなら条件成立になります。たとえば、x の値がちょうど 10 である時に処理を実行したいなら、if ( x == 10 ) { ... } のように書けばよいわけです。
なお、「 <= 」 と 「 >= 」 において、イコール記号は必ず右側に付ける必要がある事に注意してください。 順序が逆だと使用できません。慣れないうちはハマりやすいので、気を付けましょう。
続いて、複数の条件を組み合わせて判定する方法についてです。
たとえば、「 x が 10 よりも小さく、かつ、y も 20 より小さい 」 という条件のときだけ、処理を行いたいとしましょう。 この場合、普通に if 文を2個使って、以下のように書く事もできます:
でも、実は以下のように 1 つの if 文で書く事もできます:
これで、全く同じ処理を実現できます。シンプルになりましたね。
ここで使用している 「 && 」 は一般に論理演算子と呼ばれるものの一つで、 上の例のように、複数の条件を組み合わせてまとめるのに便利です。
具体的に「 && 」は、左右の条件が両方とも成立している場合だけ、全体的に条件成立となります。 つまりどちらか片方でも不成立であれば、全体的には不成立です。
論理演算子には、以下のようなものがあります:
「 || 」 は 「 && 」 の兄弟のようなもので、 たとえば if ( x < 10 || y < 20 ) { ... } と書けば、 「 x が 10 よりも小さいか、もしくは y が 20 より小さいか 」のどちらか片方だけでも成立していれば、その時点で if の中の処理が実行されます。 両方成立していても実行されます。
「 ! 」 はちょっとパターンが違って、 たとえば if ( !( x < 10 ) ) { ... } と書けば、 「 x が 10 よりも小さくない 」場合に、if 文の中の処理が実行されるようになります。 他の論理演算子と組み合わせて使うと結構便利なのですが、 あまり考えずに場当たり的に使いすぎると、あとで条件を読みかえした時に、「 旗揚げゲーム 」のように紛らわしくなる事もあります。もっとも、それは他の論理演算子や比較演算子にも言える事です。
そのような場合、条件全体を図などに書いてよく見直すと、実はもっとシンプルに書ける、という可能性もあります。 また、else if 文が何個も連なる場合などには、それらの順序を少し入れかえると、条件が途端にシンプルになったりもします。 解読しづらい複雑な記述内容の条件は、たくさんバグを生み出しかねない強敵です。 読みやすくなるように、うまく工夫しましょう。