if ステートメント
変数のデータや関数の戻り値が、ある条件を満たしているかどうかによって処理を分岐させるために用いるのが if ステートメントと呼ばれるものです。使い方は、
if(条件式) 条件が真のときの処理; else 条件が偽のときの処理;
if(条件式){ 条件が真のときの処理 }else{ 条件が偽のときの処理 }
のように書きます。「条件式の真偽」というのは「式の計算結果が 0 かどうか」です。整数、実数にかかわらず、計算結果が 0 であれば偽 (false)、0 以外の値であれば真 (true) とみなされます。数式の計算結果が文字列 (string) 型の場合は、その文字列の長さが 0 かどうかで真偽が判定されます。if ステートメントの「条件が〜のときの処理」というのは、セミコロン 1 個分の文もしくは { } で囲まれたブロックとします。分岐する処理の内容が 1 行だけならブロックはいりませんが、複数行の分岐内容を書きたい場合はブロック { } を使います。真のときの処理にブロックを使い、else 以後は 1 行だけなのでブロックを使わない、ということも可能です (その逆も可能です)。また、真のときだけ処理を行いたい場合には、else 以降はなくてもかまいません。それでは、分岐構文の使用例を見てみましょう。
if ステートメントの使用例
void main(){ int sugar = YesNoDialog("砂糖を入れますか?"); int milk = YesNoDialog("ミルクを入れますか?"); if(sugar){ if(milk) SysDialog("両方入れました。"); else SysDialog("砂糖だけ入れました。"); }else{ if(milk) SysDialog("ミルクだけ入れました。"); else SysDialog("ブラックです。"); } }
解説
この例のように、if ステートメントの中に if ステートメントを入れ子 (ネスト) することもできます。そのような場合は、包含関係をわかりやすくするためにブロックを使うことが望ましいです。このスクリプトでは、まず 2 つの質問の答えを sugar, milk という 2 個の変数に入れておき、その内容によって条件分岐を行っています。YesNoDialog 関数の戻り値は「はい」を押したときに 1、「いいえ」が 0 でしたね。ところで、これまでも main 関数の中では行の初めにスペース 4 個分を空白を入れてきましたが、if ステートメントのブロック内ではさらに 4 個分のスペースを入れています。このように、ブロック { } の中に入るたびに行頭のスペースを増やしていくことを「インデント」といいます。インデントは、ブロックの階層関係をわかりやすくするために重要なことです。必ず行うようにしましょう。また、このリファレンスは HTML なのでスペースを使っていますが、実際にスクリプトを書くときにはスペースでなくタブを使ったほうが便利です。次に、ブロックを使わずに if をネストすると、どのようなことが起こるか見てみましょう。
if と else の対応
void main(){ int sugar = YesNoDialog("砂糖を入れますか?"); int milk = YesNoDialog("ミルクを入れますか?"); if(!sugar) if(!milk) SysDialog("ブラックです。"); else SysDialog("???"); }
解説
このサンプルでは、条件式の反転演算子 ! を使っています。反転演算子 ! は、加減乗除などと異なり、オペランドをひとつしかとりません。この演算子の計算結果は、! の右に置かれた変数 (あるいはカッコで囲まれた数式) の値が真であると 0、儀であると 1 になります。文字通り条件を反転する演算子です。さて、スクリプトの内容はというと、まず if(!sugar) if(!milk) ですから、sugar と milk がいずれも 0 ならば「ブラックです」というメッセージが表示される、ということはおわかりでしょうか。では、「???」というメッセージが表示されるのはどのような返答を行ったときでしょう?最後の行の else が、2 個の if のどちらに対応しているかわかりますか?…そうです。この else は、インデントのとり方に惑わされると 1 個目の if と対応しているようですが、実は 2 個目の if に対応しているのです。このように、else はそれ以前の構文で最も近い if と対応付けられる、というルールがあります。しかしこのような場合は、やはり外側の if でブロックを使ってわかりやすくすることが望ましいのです。
比較演算子
C 言語には 6 種類の比較演算子があります。==, !=, >, <, >=, <= の 6 種類です。1 個目はイコールを 2 個連続して書いたもので、両辺の数値や文字列が同じかどうか調べます。2 個目は ! と = をつなげて書いたもので、両辺の値が違うかどうか調べます。あとの 4 つは数値の比較演算子で、= が付いていれば「以上」「以下」、付いていなければ「より大きい」「より小さい」ということを表します。「以上」「以下」のイコールは必ず右側なので気を付けてください。また、比較演算子 == と代入演算子 = はよく間違えるので気を付けてください。さて、これらの比較演算子の計算結果は、いずれも左辺と右辺の関係が演算子の表すところと一致していれば 1、そうでなければ 0 となります。以下に使用例を示します。
数値を比較する
void main(){ double a = 0.03, b = 0.05; if(a==b) SysDialog("a と b は等しい。"); if(a!=b) SysDialog("a と b は等しくない。"); if(a>b) SysDialog("a は b より大きい。"); if(a<=b) SysDialog("a は b 以下である。"); }
解説
a と b の数値をいろいろ変えて試してみてください。a==b と a!=b、a>b と a<=b はそれぞれ逆の条件を示しており、else 文を使っても書けることに注意してください。else 文を使って書き換え、同じ動きになるか確かめてみてください。
switch ステートメント
if ステートメントは、数式の真偽により 2 つに分岐するだけでした。整数の値によってさらに多数の分岐を行いたい場合には switch ステートメントを使います。使い方は、
switch(条件式){
case 値1: 値1のときの処理; break;
case 値2: 値2のときの処理; break;
…
default: いずれにも当てはならないときの処理;
}
のように書きます。値1、値2 など、case に使う値はコンパイルの段階で数値がわかっている定数整数式でなければなりません。case のように、コロンで終わる識別子をラベルといいます。また、switch の条件式は計算結果が整数でなければなりません。break ステートメントは switch ステートメント (など) から抜け出すために使います。break ステートメントがなければ、次に書かれている case の処理も続けて実行されます。処理は case と break の間に複数行書くことができます。いずれの case にも当てはまらなかった場合の処理を記述したい場合は default というラベルを使います。break ステートメントがなくても switch ブロックの最後の行に到達すると自動的に抜け出し、次の行に処理が移ります。使用例を見てください。
switch ステートメントの使用例
void main(){ int tmp = 0; switch(tmp){ case 1: SysDialog("tmp は 1 です。"); case 2: SysDialog("tmp は 1 かもしれないし、2 かもしれない。"); break; default: SysDialog("tmp は 0 でも 1 でも 2 でもない。"); break; case 0: SysDialog("tmp は 0 です。"); break; } }
解説
上のプログラムを変数 tmp の値をいろいろ変えて実行してみてください。case 1 の行には break ステートメントがないので次の行も実行されていることがわかりますね。最後の case 0 の行の break は無意味ですが、他のケースとの外見上の整合性を保つために書くことがあります。必ずしも default を最後に書かなければならないことはありませんし、case を数値の順に並べる必要もありません。なお、このサンプルでは tmp の値は自分で書いているので分岐する意味がありませんが、実際のプログラムでは switch ステートメントの条件式には、実行中に計算結果が変化しうる数式を書きます。