Lesson 2

条件分岐

Lesson 2 Chapter 1
条件分岐

プログラムは、記述した順に実行されるのが基本ですが、変数の値などによって実行する処理を分けたい場合があります。このChapterでは、C言語のif文や switch文を使って、条件によって処理を分岐させる方法について解説します。また、C言語の条件分岐を理解するためには「論理式」というものを理解する必要があります。論理式とは、主に関係演算子や論理演算子、関数を用いて記述された式のことで、式を判定(評価)した結果が正しい(真)か正しくない(偽)かによって、処理が分岐します。いろいろな演算子が存在するので、使い方を一つ一つ理解しながら学習を進めましょう。

関係演算子

演算子 読み方 使い方 条件
< 小なり A < B AがBより小さい
> 大なり A > B AがBより大きい
<= 小なりイコール A <= B AがB以下
>= 大なりイコール A >= B AがB以上

上記の表がC言語で登場する「関係演算子」になります。読み方については、一般的には上記の表の読み方になります。
では「関係演算子」を使って、2つの値をキーボードから入力して比較を行い、結果を表示するプログラムを書いてみましょう。

Compare1.c
#include <stdio.h>
int main(void) {
  int a,b;
  puts("整数を2回入力してください");
  scanf("%d%d", &a, &b);
  printf("%d < %d  → 結果:%d\n", a ,b ,a < b);
  printf("%d > %d  → 結果:%d\n", a ,b ,a > b);
  printf("%d <= %d → 結果:%d\n", a ,b ,a <= b);
  printf("%d >= %d → 結果:%d\n", a ,b ,a >= b);
  return 0;
}
Compare1.exe(異なる整数)
整数を2回入力してください
1
2

1 < 2  → 結果:1
1 > 2  → 結果:0
1 <= 2 → 結果:1
1 >= 2 → 結果:0

異なる整数を入力した結果について確認していきます。「1 < 2」を比較結果が「1」となっています。論理式を評価(比較)した結果、正しい場合のことを論理式では「真」と呼びます。逆に論理式の評価が間違っていた場合は「偽」と呼びます。また、数学であれば「1は2よりも小さい」ですが、C言語では少し意味合いが異なり、「1は2よりも小さいか」という比較を行います。実際に1は2よりも小さいので、この比較結果は「真」になります。
「1 > 2」は「1は2よりも大きいか」を評価します。正しくないため、結果は「偽」になります。
「1 <= 2」は演算子「<=」を使用しています。これは「1が2以下か」という評価を行います。これは正しいため、結果は「真」になります。
「1 >= 2」は演算子「>=」を使用して「1が2以上か」という評価を行います。正しくないため、評価結果は「偽」になります。

Compare1.exe(同じ整数)
整数を2回入力してください
2
2

2 < 2  → 結果:0
2 > 2  → 結果:0
2 <= 2 → 結果:1
2 >= 2 → 結果:1

次に、同じ整数を入力した結果について確認していきます。
「2 < 2」を比較結果が「0」となっています。「2は2よりも小さいか」という評価を行います。同じ整数に大小はないため、比較結果は「偽」となります。
「2 > 2」も同様に「偽」となります。
「2 <= 2」は「2が2以下か」という評価を行います。演算子の「=」からも読み取れるように、同じ整数であれば正しい評価となるため「真」となります。
「2 <= 2」は「2が2以上か」という評価を行います。日本語の「以下、以上」には同じ値を含みますので、こちらも「真」となります。

等価演算子

演算子 読み方 使い方 条件
== イコールイコール A == B AとBが等しい
!= ノットイコール A != B AとBが等しくない

上記がC言語で使用される「等価演算子」になります。等しいか、等しくないかを評価する演算子になります。実際にコードを書いて確認してみましょう。

Compare2.c
#include <stdio.h>
int main(void) {
  int a;
  puts("整数を入力してください");
  scanf("%d", &a);
  printf("入力された整数aは%dです\n整数2と比較します\n", a);
  
  printf("%d == 2  → 結果:%d\n", a ,a == 2);
  printf("%d != 2  → 結果:%d\n", a ,a != 2);
  return 0;
}
Compare2.exe
整数を入力してください
2
入力された整数aは2です
整数2と比較します
2 == 2  → 結果:1
2 != 2  → 結果:0

結果について確認していきます。
「2 == 2」を比較した結果は「1」となっています。これは「2と2は等しいか」という評価を行います。正しいため「真」となります。
「2 != 2」は「2と2は等しくない」という評価を行います。異なる整数であれば「真」となりますが、同じ整数の評価は「偽」となります。

論理演算子

論理演算子は、2つ以上の論理式を組み合わせて論理式を作るための演算子です。条件が成立したら「真」を返し、不成立ならば「偽」を返します。

&&(論理積)

「&&」は「論理積」と呼ばれ、複数の論理式が全て「真」の場合に真を返し、それ以外は「偽」を返します。

||(論理和)

「||」は「論理和」と呼ばれ、複数の論理式が全て「偽」の場合に「偽」を返し、それ以外は「真」を返します。コードを書いて確認しましょう。

Compare3.c
#include <stdio.h>
int main(void) {
	puts("【論理積】");
	printf("1.「1 > 2 && 1 > 2」は%dです\n", 1 > 2 && 1 > 2);
	printf("2.「1 < 2 && 1 > 2」は%dです\n", 1 < 2 && 1 > 2);
	printf("3.「1 < 2 && 1 < 2」は%dです\n", 1 < 2 && 1 < 2);
	puts("【論理和】");
	printf("4.「1 < 2 || 1 > 2」は%dです\n", 1 < 2 || 1 > 2);
	printf("5.「1 < 2 || 1 < 2」は%dです\n", 1 < 2 || 1 < 2);
	printf("6.「1 > 2 || 1 > 2」は%dです\n", 1 > 2 || 1 > 2);
	return 0;
}
Compare2.exe
【論理積】
1.「1 > 2 && 1 > 2」は0です
2.「1 < 2 && 1 > 2」は0です
3.「1 < 2 && 1 < 2」は1です
【論理和】
4.「1 < 2 || 1 > 2」は1です
5.「1 < 2 || 1 < 2」は1です
6.「1 > 2 || 1 > 2」は0です

「&&」は、2つの論理式が「真」の場合に「真」を返すので、3番目は条件を満たすため、結果は「1(真)」となります。1番目は両方、2番目は片方が「偽」となるため、結果は「0(偽)」となります。 「||」は、2つの論理式が「偽」の場合に「偽」を返すので、4番目は片方、5番目は両方が「真」となるため、結果は「1(真)」となります。6番目は両方とも「偽」となるため、結果は「0(偽)」となります。

論理否定演算子

!演算子(論理否定)は「真」と「偽」の結果がひっくり返す演算子です。!演算子を使う場合は対象の論理式を括弧で括る必要があります。先ほどのコードの結果をひっくり返してみましょう。

Compare3.c
#include <stdio.h>
int main(void) {
	puts("【論理積】");
	printf("1.「1 > 2 && 1 > 2」は%dです\n", 1 > !(2 && 1 > 2));
	printf("2.「1 < 2 && 1 > 2」は%dです\n", 1 < !(2 && 1 > 2));
	printf("3.「1 < 2 && 1 < 2」は%dです\n", 1 < !(2 && 1 < 2));
	puts("【論理和】");
	printf("4.「1 < 2 || 1 > 2」は%dです\n", 1 < !(2 || 1 > 2);
	printf("5.「1 < 2 || 1 < 2」は%dです\n", 1 < !(2 || 1 < 2);
	printf("6.「1 > 2 || 1 > 2」は%dです\n", 1 > !(2 || 1 > 2);
	return 0;
}
Compare3.exe
【論理積】
「1 > 2 && 1 > 2」は1です
「1 < 2 && 1 > 2」は1です
「1 < 2 && 1 < 2」は0です
【論理和】
「1 < 2 || 1 > 2」は0です
「1 < 2 || 1 < 2」は0です
「1 > 2 || 1 > 2」は1です

「Compare2.exe」の結果と比較すると、結果の「真」と「偽」が逆になっていることが分かります。

式と評価

Hyoka.c
#include <stdio.h>
int main(void) {
  int a;
  int b;
  puts("「!(((a = b) == 2))」を評価します");
  puts("bの値を入力してください。");
  scanf("%d", &b);
  printf("評価結果%d", !(((a = b) == 2)));
  return 0;
}
Hyoka.exe
2
評価結果:0

「式」とは何らかの演算を行う命令で、その結果である値を返します。式を実行して値を取得することを式の「評価」といい、値は「評価」の結果です。
上記のコードは「!(((a = b) == 2))」の評価結果を出力するプログラムです。 下記の順に演算処理され、評価します。
1. aにbを代入する
2. 等価演算子により「aと2が等しいか」を評価する
3. !演算子により評価をひっくり返す
プログラミングに慣れるまでは、この式と評価の処理順がイメージしにくいかもしれませんが、ある程度コードを読み書きすることで、自然と身についていきます。

式文と空文

// 式文
puts("こんにちは!");
    
// 空文
;

式文と空文について解説します。C言語では「;」(セミコロン)で終わる文のことを「式文」、「;」だけ書かれた文のことを「空文」と呼びます。

Lesson 2 Chapter 2
if文

if文(その1)if単発

「if」(イフ)という文を使うと、条件に応じてプログラムを分岐させることができます。if文で式を評価した結果が「真」の場合は、指定した処理を実行します。if文は2通りの書き方があります。

if文の書き方①
if (式) 文;
if文の書き方②
if (式) {
  文;
  …
} 

構文「if (式) 文;」の条件分岐の対象は1文だけ

「if (式) 文A;文B;」とコーディングした場合、if文の分岐対象は「文A」だけである点に注意が必要です。文Bはif文の分岐対象ではないため、必ず実行します。複数の文をif文で分岐したい場合はブロック「{}」を使いましょう。

if1.c
#include <stdio.h>
int main(void) {
    int year;
    puts("西暦を入力してください");
    scanf("%d", &year);

    if (year % 4 == 0) puts("うるう年です");

    if (year % 4 == 0) {
        printf("うるう年");
        printf("です\n");
    }
    return 0;
}
実行結果
if1.exe
西暦を入力してください
2028
うるう年です
うるう年です

上記のプログラムは、ブロックを使わないif文と、ブロックを使うif文の両方が記述されています。うるう年は4で割り切れる西暦が該当するため、式は「year % 4 == 0」となります。式が「真」の場合は「うるう年です」と2回表示されます。ブロックつきのif文は、ブロック内の文が全て実行されていることが分かります。

if文(その2)if, else

if文に「else」 (エルス)を組み合わせると、式が「偽」ときに実行する処理も指定することが可能です。

elseの書き方①
if (式) 文A; else 文B;

複数の文を実行したい場合はブロックを使います。ブロック内の文はインデントをつけて読みやすいようにします。

elseの書き方②
if (式) {
  文A;
  …
} else {
  文B;
  …
} 

前述の西暦を入力するプログラムに「else」を追加して「うるう年ではない」分岐を書いてみましょう。

if2.c
#include <stdio.h>
int main(void) {
    int year;
    puts("西暦を入力してください");
    scanf("%d", &year);

    if (year % 4 == 0) puts("うるう年です"); puts("うるう年ではありません");

    if (year % 4 == 0) {
        printf("うるう年");
        printf("です\n");
    } else {
        printf("うるう年");
        printf("ではありません\n");
    }
    return 0;
}
実行結果
if2.exe
西暦を入力してください
2029
うるう年ではありません
うるう年ではありません

if文(その3)if, else if, else

「else if」 (エルスイフ)は、最初の条件が「偽」の場合、次の条件を判定して分岐する構文で、下記のように書きます。式Aが「真」の場合は文Aを実行し、式Aが「偽」の場合は、式Bを判定します。式Bが「真」は文Bを実行し、式Bが「偽」の場合は文Cを実行します。「else if」は何回でも追加可能なため、「else if else if...」のように記述して条件を増やすことができます。最後の「else」については省略することも可能です。

else ifの書き方①
if (式A) 文A; else if(式B) 文B; else 文C; 
else ifの書き方②
if (式A) {
  文A;
  …
} else if (式B){
  文B;
  …
} else {
  文C;
  …
}

先ほどのプログラムに「else if」を追加してサッカーワールドカップ開催年の条件を書いてみましょう。

if3.c
#include <stdio.h>
int main(void) {
    int year;
    puts("西暦を入力してください");
    scanf("%d", &year);

    if (year % 4 == 0) puts("うるう年です");
    else if (year % 4 == 2) puts("サッカーワールドカップ開催年です");
    else puts("うるう年でもサッカーワールドカップ開催年でもありません");

    if (year % 4 == 0) {
        printf("うるう年");
        printf("です\n");
    } else if (year % 4 == 2) {
        printf("サッカーワールドカップ開催年");
        printf("です\n");
    } else {
        printf("うるう年でもサッカーワールドカップ開催年でも");
        printf("ありません\n");
    }
    return 0;
}
実行結果
if3.exe
西暦を入力してください
2026
サッカーワールドカップ開催年です
サッカーワールドカップ開催年です

サッカーワールドカップは「year % 4 == 2」の条件を満たす年に開催されるため、「2026」を入力するとうるう年の条件には該当せず、サッカーワールドカップ開催年の条件と満たします。

入れ子となったif文

処理の中にさらに処理を含めることを「入れ子」といいます。if文の「入れ子」について、基本となる構文の書き方は下記のようになります。

入れ子となったif文の書き方①
if (式A) if(式B) 文B;
入れ子となったif文の書き方②
if (式A) {
  if(式B) {
    文B;
  }
}

2-1_2.png

条件の式Aを判定した結果が「真」の場合、「入れ子」の条件の式Bが実行されます。「入れ子」となっているif文のプログラムを書いてみましょう。

if3.c
#include <stdio.h>
int main(void) {
    int year;
    puts("西暦を入力してください");
    scanf("%d", &year);
    
    if (year >= 2000)
      if (year % 4 == 0) puts("うるう年です");
      else if (year % 4 == 2) puts("サッカーワールドカップ開催年です");
      else puts("うるう年でもサッカーワールドカップ開催年でもありません");
    
    
    if (year >= 2000) {
      if (year % 4 == 0) {
          printf("うるう年");
          printf("です\n");
      } else if (year % 4 == 2) {
          printf("サッカーワールドカップ開催年");
          printf("です\n");
      } else {
          printf("うるう年でもサッカーワールドカップ開催年でも");
          printf("ありません\n");
      }
    }
    return 0;
}
実行結果
if3.exe
西暦を入力してください
2027
うるう年でもサッカーワールドカップ開催年でもありません
うるう年でもサッカーワールドカップ開催年でもありません

まず入力した西暦が2000以上かを「year >= 2000」で判定しています。2000以上だった場合のみ「入れ子」となってるif文の処理を実行します。なので、最1999以下の値を入力すると、最初の判定で条件を満たさないため、「入れ子」となっている処理は実行されません。

条件演算子

条件演算子は、if文のような分岐を式の中で行うための演算子です。項(演算の対象)が3個あるので、三項演算子とも呼びます。条件演算子は次のように書きます。式Aの値が0以外のとき(条件が成立したとき)には式Bの値を返却して、式Aの値が0のとき(条件が不成立のとき)には式Cを返します。?(クエスチョン)や:(コロン)の前後に空白を入れましたが、空白を入れずに詰めて書いても構いません。

条件演算子
式A ? 式B : 式C;

上記の式は「式Aが成立したら式B、不成立ならば式Cの値を返す」のように読むと、動作を理解しやすいでしょう。if文で書くと、次のようなイメージになります。

条件演算子をif文で表現
if (式A) 式B; else 式C;

複数の条件演算子を並べて書くことで、より複雑な分岐も可能です。例えば、2個の条件演算子を並べて、次のように書けます。

複数の条件演算子
式A ? 式B : 式C ? 式D : 式E;

上記の式は「式Aが成立したら式Bを返し、式Aが不成立で式Cが成立したら式Dを返し、式Cも不成立ならば式Eの値を返す」のように解釈します。if文で書くと、次のようなイメージです。

複数の条件演算子をif文で表現
if (式A) 式B; else if (式C) 式D; else 式E;

条件演算子を使ってコードを書いてみましょう。キーボードから入力した西暦が1989から2018なら「"HEISEI"」、2019以上であれば「"REIWA"」それ以外の西暦は「"ERROR"」を表示するプログラムを書いてください。if文は使わずに、条件演算子を使って書きます。出力を行うprintf関数も、3回呼び出すのではなく、1回だけ呼び出します。

if4.c
#include <stdio.h>
int main(void) {
  int year;
  puts("西暦を入力してください");
  scanf("%d", &year);
    
  printf(year >= 1989 && year <= 2018 ? "HEISEI" : year >= 2019 ? "REiWA" :  "ERROR");
   
   return 0;
}
実行結果
if4.exe
西暦を入力してください
2027
REiWA

Lesson 2 Chapter 3
switch文

switch文

「switch」 (スイッチ)は、値によってプログラムの処理を分岐させることができる構文です。一般的に条件分岐と呼ばれる処理で、「case」(ケース)で複数の条件を書くことができます。

switch文の書き方
switch (式) {
  case 値A:
    文A;
    break;
  case 値B:
    文B;
    break;
  …
  default:
    文C;
}

2-1_1.png

「case」ごとに異なる値を書き、:(コロン)の後に実行したい文を書きます。文は複数でも問題ありません。各「case」の最後に「break」 (ブレイク)文を書くのが一般的です。「break」文を書くことで、switch文の処理から抜けます。default (デフォルト)は、今まで書いた「case」の条件に該当しなかった場合に実行する処理を書きます。「case」は複数書けますが、defaultは1つだけ書きます。また、必要がなければ「default」は省略可能です。「switch」文は以下の流れで処理を実行します。
1. 式を評価して値を取得する
2. 取得した値とcase値Aが等しいか判定する
3. 値Aと等しい場合は文Aを実行する
4. breakでswitchの処理から抜ける
取得した値が値Aと値B、両方と等しくない場合はdefaultに分岐して、文Cを実行します。

「case」「defalut」の末尾は:(コロン)

今まで登場した文の最後は;(セミコロン)でしたが、「switch」文は:(コロン)を使って条件分岐を行います。間違いやすいので気をつけましょう。

プログラミングの上達のコツは、どのようにソースを書けば期待通りに動作するか頭の中でイメージすることが大切です。ソースの例を確認する前に、どのようなコーディングになるか、期待通りに動作するかイメージしてみましょう。今回はscanf関数で読み取った整数の値によって処理が分岐するswitch文を書きます。

switch.c
#include <stdio.h>
int main(void) {
    int number;
    puts("1から3までの整数いずれかを入力してください");
    scanf("%d", &number);
    
    switch (number) {
      case 1:
        printf("入力された値は%dです\n", number);
        break;
      case 2:
        printf("入力された値は%dです\n", number);
        break;
      case 3:
        printf("入力された値は%dです\n", number);
        break;
      default :
        puts("1から3までの整数ではありません");
    }
    return 0;
}
1を入力した場合の実行結果
switch.exe
1から3までの整数いずれかを入力してください
1
入力された値は1です
4を入力した場合の実行結果
switch.exe
1から3までの整数いずれかを入力してください
4
1から3までの整数ではありません