3.2 if文
3.2.1 プログラムを分岐させる
これまでは、プログラムは main() 関数の中を上から下へ誠実に実行してきました。入力を学んだことによって、さらに動的な結果を得られることもできるようになりましたが、プログラムは常に1本の道を進むだけでした。
ここではさらに、値を判定してプログラマの意図に従ってプログラムを動かします。すなわちプログラムを分岐させます。値を判定する方法は、前項の「3.1 真偽の判定」で学習しました。
プログラムを分岐させるもっとも基本的な制御文は if 文です。if 文は「~が~であれば~する」というプログラム制御を可能にします。~が~であれば という部分は関係演算子や論理演算子を用いた条件式で表現することができます。
if (条件式) 文
条件式には真、又は偽を表す値(すなわち、最終的には数値型)を指定します。if 文は条件式の結果が真の場合のみ実行され、そうでなければ実行されません。より単純にいえば、条件式に 0 以外の値が指定されたときのみ実行されるのです。
#include <stdio.h> int main() { int iBool; printf("0 又はそれ以外の値を入力してください>"); scanf("%d" , &iBool); if (iBool) printf("真が入力されました\n"); if (!iBool) printf("偽が入力されました\n"); return 0; }
コード1を起動すると、値の入力が求められるので 0 又はそれ以外の値(すなわち真か偽)を入力します。すると、プログラムは if 文で入力された値を調べ、その結果に応じて表示する文字が変化します。最初の if 文は iBool が真であれば、その次の if 文は否定演算子 ! で否定しているので iBool が偽であれば、続く文を実行します。
iBool が偽であれば実行する if 文を書く場合、!iBool ではなく iBool == 0 と書いても同じ結果が得られます。if ( ! iBool) という文は英語圏の人が見ると直観的に if not iBool と感じることができますが、日本人は if (iBool == 0) ... と書いたほうが理解が容易かもしれません。これは好みの問題でしょう。
コード1では「~が真でなければ」という表現を !iBool という否定演算子を用いた if 文で実現しています。しかし、このように iBool を調べて、結果を真だった場合と偽だった場合の 2 つに分岐させたい場合は else 部を使う方法があります。else 部は if 文とワンセットで使われるもので、if で評価した条件式が偽だった場合に実行されます。else 部を用いた if 文は次のように記述します。
if (条件式) 文1 else 文2
if 文の条件式が真であれば文1が実行され、そうでなければ else キーワードの後の文2が実行されます。else の前には必ず if が必要であり、if 文がない場所で else 部を指定することはできません。else 部を持つ if 文を用いればコード1を次のように改良することができます。
#include <stdio.h> int main() { int iBool; printf("0 又はそれ以外の値を入力してください>"); scanf("%d" , &iBool); if (iBool) printf("真が入力されました\n"); else printf("偽が入力されました\n"); return 0; }
コード2はコード1をより最適な形に改良したものです。このように else 部を用いれば、iBool が偽であるかどうかを評価する必要がなくなるため、無駄な処理を省略することができます。else 部は if 文の評価が偽だった場合に実行されます。もちろん、真であれば else 部は実行されません。
また、if と else は次のように入れ子(同じ形の箱などを大きさの順に幾つも重ねて中へ入れるようにしたもののこと。プログラミングでは同一の命令を重ねることを入れ子、又はネストと言う)にすることができます。これは「~であれば~する。そうでなければ~する。そうでなければ~する…」というプログラムの流れを作ることができるようになり、複雑な制御や解析を行う場合によく使われます。ただし、入れ子関係は可能な限り少なくし、読みやすいプログラムを書けるように心がけましょう。
#include <stdio.h> int main() { char chVar; printf("Do you like C language? Y/N>"); scanf("%c" , &chVar); if (chVar == 'Y' || chVar == 'y') printf("Good! Just go for it!!\n"); else if (chVar == 'N' || chVar == 'n') printf("Why are you studying C language?\n"); else printf("Error\n"); return 0; }
コード3は、プログラムに「あなたはC言語が好きか?」と尋ねられ、Y (Yes)または N (No)を入力して問いに答えるという一般的なコマンドラインの対話を想定したものです。プログラムは入力された値を調べ、「Y が入力された場合」、「N が入力された場合」、「それ以外の値が入力された場合」の3パターンに分岐させる必要があるものとします。
プログラムでは、最初の if 文で、入力された文字を格納する chVar 変数を調べ、'Y' または 'y' のいずれかが入力されているかどうかを調べています。この評価の結果が偽であれば、else が実行されますが、この if 文の else では、さらに if 文を用いているため、入れ子構造になっています。
3.2.2 複合文
これまでのプログラムでは、if や else 部によってプログラムを分岐させることができましたが、実行できたのは1文のみでした。これでは、if 文で複数の文を指定することができません。例えば、次のようなプログラムは誤りです。
if (exp) iVar += 50; printf("iVar = %d" , iVar); else ...
if 文で指定した条件 exp が真のとき、iVar += 50 は if 文として実行されますが printf() 関数の時点で元の制御に戻ってしまいます。そのため、else では直前の if 文が存在しないと判断されコンパイルエラーが発生してしまいます。if で複数の文をまとめて実行させたい場合、複合文(複文、ブロックとも呼ばれる)を用いる必要があります。
{ 文1 文2 文N... }
複合文は { ではじまり } で終わります。文を記述できる場所ならば、どこにでも書くことができます。{ } の内部は複数の文で構成され、何らかの文の本体として機能させることができます。例えば、関数の本体は複合文であると考えることができます。C 言語では、文の末尾にセミコロン ; を指定するのが普通ですが、複合文の末尾には ; を付けません。又、複合文は入れ子にすることができます。
暗黙のルールとしては、複合文の内部はインデントを1段階深くするという規則があります。これは C の構文ではないので、従わなくてもコンパイルすることができますが、非常に読みづらいソースになってしまいます。もし以下のようなプログラムソースを書いたとしたら、あなた以外に読んでくれる人はいないと思っていいでしょう。
if (a == b) { printf("..."); if (a == c) { printf("...") } } else { printf("..."); }
共同開発やオープンソースの開発を考えて、初心者のうちから正しいソースの書き方を習慣づけてください。 統合開発環境のプログラミング専用のエディタでは自動的に整形してくれたりもしますが、単純なテキストエディタを用いている場合は意識する必要があります。近年では「移植」や「拡張」などの機会が多く、そのたびに過去に書いたソースを読み直すことになります。 次のように記述すれば読みやすくなります。
if (a == b) { printf("..."); if (a == c) { printf("...") } } else { printf("..."); }
このように記述することで、文がどの複合文に属しているかを判断しやすくなります。
#include <stdio.h> int main() { int iBool; printf("0 又はそれ以外の値を入力してください>"); scanf("%d" , &iBool); if (iBool) { printf("真が入力されました\n"); return 1; } else { printf("偽が入力されました\n"); return 0; } }
このプログラムは、真か偽を表す数値を入力し、その結果に応じてシステムに返す値を変化させています。ネストされた複合文の内部でも関数を終了させることができるため、if や else で指定している複合文の内部でプログラムを終了させています。
コード4の if-else 文の処理は printf() 関数と return キーワードを用いた2つの文から構成されているため、単一の文として表現することはできません。そこで、複合文を用いて複数の文を指定しています。return が返す値がどのように利用されるかはシステムによって異なります。詳細は、あなたが使っているシステムについて詳しく勉強してください。システムに返した値のその後は C 言語の管轄ではないのです。