[前へ]   [目次へ]   [次へ]

条件分岐「if / else」(後編)(C/C++)


今回は「それ以外の場合」を意味する「 else 」です。

前回は if による条件分岐について書きました。
if だけでも分岐を書くことは出来ますが、条件が成立した場合だけでなく、
成立しなかった場合だけ実行したいコードもよくあります。

成立しなかった場合だけ実行する処理を記述するには、 else を使います。
else も if 同様、C言語の数少ないキーワードのひとつです。

else は必ず if に続いて記述されなければなりません。
else は「それ以外の場合」なので何の「それ以外の場合」なのか示さなければならないためです。

記述方法は、基本的に if と同様、以下の様になります。

else それ以外の時の処理

else には条件式はありません。
所属する if の条件式が偽になった時に「それ以外の時の処理」が実行されます。

前回のソースを元に例を示します。
<  1>
<  2>
<  3>
<  4>
<  5>
<  6>
<  7>
<  8>
<  9>
< 10>
#include <stdio.h>

int main(void)
{
   
int n=5;//とりあえず5を入れて定義
   
if(n)puts("nは0以外-1行構文");//前回同様。
   
else puts("nは0-1行構文");//1行構文。nが0だったら文字列表示
   
puts("分岐終了。ここはnがいくつでも通る");
   
return 0;
実行結果:
nは0以外-1行構文
分岐終了。ここはnがいくつでも通る


7行目に6行目に対する else が追加されました。
この例では6行目の if は真だったため、7行目の else の処理は無視されています。

次に、5行目で n に5ではなく、0を代入した場合です。
<  1>
<  2>
<  3>
<  4>
<  5>
<  6>
<  7>
<  8>
<  9>
< 10>
#include <stdio.h>

int main(void)
{
   
int n=0;//とりあえず0を入れて定義
   
if(n)puts("nは0以外-1行構文");//前回同様。
   
else puts("nは0-1行構文");//1行構文。nが0だったら文字列表示
   
puts("分岐終了。ここはnがいくつでも通る");
   
return 0;
実行結果:
nは0-1行構文
分岐終了。ここはnがいくつでも通る


n の値が変化したことにより、6行目の if が偽になりました。
よって真の時の処理が実行されないのは前回の通り。
その代わり、今度は else にある「それ以外の時の処理」が実行されています。
つまり、 else の処理は「所属する if が偽の時の処理」でもあります。

また、 if の時同様「それ以外の時の処理」のところでブロックを開くと、
そのブロックが「それ以外の時の処理」になり、そのブロックの中全てが「それ以外の時の処理」になります。

<  1>
<  2>
<  3>
<  4>
<  5>
<  6>
<  7>
<  8>
<  9>
< 10>
< 11>
< 12>
< 13>
< 14>
< 15>
< 16>
#include <stdio.h>

int main(void)
{
   
int n=5;//とりあえず5を入れて定義
   
if(n){//前回同様。
      
puts("nは0以外-ブロック構文");
      puts(
"ここもifの範囲内。真の時のみ実行される");
   }
//ifブロックの終点
   
else{//6行目のifブロックの終点に続けているので、このelseの所属は6行目のif
      
puts("nは0-ブロック構文");
      puts(
"ここもelseの範囲内。ifが偽の時のみ実行される");
   }
//elseブロックの終点
   
puts("分岐終了。ここはnがいくつでも通る");
   
return 0;
実行結果:
nは0以外-ブロック構文
ここもifの範囲内。真の時のみ実行される
分岐終了。ここはnがいくつでも通る


if が真になったため、 else ブロックは無視されています。

次に、5行目でnに5ではなく、0を代入した場合です。
<  1>
<  2>
<  3>
<  4>
<  5>
<  6>
<  7>
<  8>
<  9>
< 10>
< 11>
< 12>
< 13>
< 14>
< 15>
< 16>
#include <stdio.h>

int main(void)
{
   
int n=0;//とりあえず0を入れて定義
   
if(n){//前回同様。
      
puts("nは0以外-ブロック構文");
      puts(
"ここもifの範囲内。真の時のみ実行される");
   }
//ifブロックの終点
   
else{//6行目のifブロックの終点に続けているので、このelseの所属は6行目のif
      
puts("nは0-ブロック構文");
      puts(
"ここもelseの範囲内。ifが偽の時のみ実行される");
   }
//elseブロックの終点
   
puts("分岐終了。ここはnがいくつでも通る");
   
return 0;
実行結果:
nは0-ブロック構文
ここもelseの範囲内。ifが偽の時のみ実行される
分岐終了。ここはnがいくつでも通る


この場合は、6行目で開いたブロックの終点、9行目までが if の範囲になり、
さらに10行目から13行目までが else ブロックです。
if が偽になったことにより if ブロックは全てなかったことにされ、
代わりに else ブロックが実行されています。


次に、 else if についてです。
else if は「条件2」「条件3」のようなイメージで使うことが出来ます。
<  1>
<  2>
<  3>
<  4>
<  5>
<  6>
<  7>
<  8>
<  9>
< 10>
< 11>
< 12>
< 13>
< 14>
< 15>
< 16>
< 17>
< 18>
< 19>
< 20>
< 21>
< 22>
< 23>
< 24>
#include <stdio.h>

int main(void)
{
   
int n=25;//とりあえず25を入れて定義
   
if(n>=100){//nが100以上
      
puts("nは100以上-ブロック構文");
      puts(
"ここもifの範囲内。真の時のみ実行される");
   }
//ifブロックの終点
   
else if(n>=10){//nが10以上
      
puts("nは10〜99-ブロック構文");
      puts(
"ここはelse ifの範囲内。6行目のifが偽で10行目のelse ifが真の時のみ実行される");
   }
//else ifブロックの終点
   
else if(n>=1){//nが1以上
      
puts("nは1〜9-ブロック構文");
      puts(
"ここは2つ目のelse ifの範囲内。6行目のifと10行目のelse ifが偽で14行目の2つ目のelse ifが真の時のみ実行される");
   }
//else ifブロックの終点
   
else{
      puts(
"nは0以下-ブロック構文");
      puts(
"ここはelseの範囲内。上記のifとelse ifが全て偽の時のみ実行される");
   }
//elseブロックの終点
   
puts("分岐終了。ここはnがいくつでも通る");
   
return 0;
実行結果:
nは10〜99-ブロック構文
ここはelse ifの範囲内。6行目のifが偽で10行目のelse ifが真の時のみ実行される
分岐終了。ここはnがいくつでも通る


if 〜 else if 〜 else による4択分岐です。
if から始まり、 else if を0個以上つなぎ、 else が最後に来ます。
else if をつなぐ数に制限はありませんが、先に書いたほうから評価され、
最初に真になる条件に遭遇した時点で後続の else if および else の評価は行われなくなります。

ところで、C/C++のキーワードには「 else if 」は存在しません。
また、 else と if の間のスペースは省略できません。
これはどういうことかというと・・・
else if は else の1行構文で、「それ以外のときの処理」が if になってるんです。
if がブロックを開いているため、 if が終了するのはブロックを閉じた時まで引き伸ばされます。
ちょっとややこしいですが、内部的にはそう処理されているはずです。

では else if の else を1行構文ではなくブロック構文で書くとどうなるでしょう。
<  1>
<  2>
<  3>
<  4>
<  5>
<  6>
<  7>
<  8>
<  9>
< 10>
< 11>
< 12>
< 13>
< 14>
< 15>
< 16>
< 17>
< 18>
< 19>
< 20>
< 21>
< 22>
< 23>
< 24>
< 25>
< 26>
< 27>
< 28>
#include <stdio.h>

int main(void)
{
   
int n=25;//とりあえず25を入れて定義
   
if(n>=100){//nが100以上
      
puts("nは100以上-ブロック構文");
      puts(
"ここもifの範囲内。真の時のみ実行される");
   }
//ifブロックの終点
   
else{
      
if(n>=10){//nが10以上
         
puts("nは10〜99-ブロック構文");
         puts(
"ここはelse ifの範囲内。6行目のifが偽で10行目のelse ifが真の時のみ実行される");
      }
//else ifブロックの終点
      
else{
         
if(n>=1){//nが1以上
            
puts("nは1〜9-ブロック構文");
            puts(
"ここは2つ目のelse ifの範囲内。6行目のifと10行目のelse ifが偽で14行目の2つ目のelse ifが真の時のみ実行される");
         }
//else ifブロックの終点
         
else{
            puts(
"nは0以下-ブロック構文");
            puts(
"ここはelseの範囲内。上記のifとelse ifが全て偽の時のみ実行される");
         }
//elseブロックの終点
      }
   }
   puts(
"分岐終了。ここはnがいくつでも通る");
   
return 0;
こんな感じですね。これはさっきのと同じ結果になります。
else if と書いたほうが感覚的に分岐2、分岐3のようでわかりやすいのと、
インデントがどんどん深くなるのを止められるという二つの利点があるのがおわかりでしょうか。


次に、1行構文を用いる時には、注意が必要なことがあります。
まず、以下のソースを見てください。
<  1>
<  2>
<  3>
<  4>
<  5>
<  6>
<  7>
<  8>
<  9>
< 10>
< 11>
#include <stdio.h>

int main(void)
{
   
int n=0;
   
if(n>=5)
      
if(n<=10)puts("nは5〜10です");
   
else puts("nは5より小さい");
   puts(
"分岐終了。ここはnがいくつでも通る");
   
return 0;
6行目、7行目で if の1行構文を多重しています。
どうなっているのかというと、6行目の if の「真の時の処理」が7行目の if(n<=10) なんです。
そして、7行目の if の「真の時の処理」が puts("nは5〜10です") になっています。
ここで、7行目の puts("nは5〜10です") が実行されるには2つの if が両方真でなければなりません。
よって、6〜7行目は結果として if((n>=5)&&(n<=10))puts("nは5〜10です") と同じになるわけです。

さて、問題は8行目の else です。
表示されるメッセージやインデントを考慮すると意図したのは6行目の if に対しての else のようです。
ところが、コンパイラは表示される文字列を意味解析してはくれませんし、インデントも気にしません。
よく見ると if の終了直後に続けるという else の条件は6行目、7行目の if 両方が満たしています。
実は、このようなことをすると else がどちらに所属するかはコンパイラが勝手に決めてしまいます。
つまり7行目の if に対しての else と解釈される可能性もあります。

コンパイラ任せで処理されては困るので、こういう状況では1行構文を使えません。
この例の場合は6行目の if でブロック構文を使うことで曖昧さを消滅させます。
<  1>
<  2>
<  3>
<  4>
<  5>
<  6>
<  7>
<  8>
<  9>
< 10>
< 11>
< 12>
#include <stdio.h>

int main(void)
{
   
int n=0;
   
if(n>=5){
      
if(n<=10)puts("nは5〜10です");
   }
   
else puts("nは5より小さい");
   puts(
"分岐終了。ここはnがいくつでも通る");
   
return 0;
こうすれば、7行目の if と9行目の else を切り離すことができ、6行目の if に対するものであると必ず解釈されます。


次回はもう一つの条件分岐「 switch 」についての予定です。

[前へ]   [目次へ]   [次へ]

プログラミング講座 総合目次

最終更新 2008/10/17