if文 条件分岐1

if文

今までのプログラミングは、単純に上から下へ順に全てのコードを実行していくだけでした。
実際のプログラミングでは、特定の条件によって処理を分けることが頻繁にあります。
そのためには条件分岐のための構文を使います。

最も代表的な条件分岐方法がif文です。


#include <stdio.h>

int main()
{
    char str[] = "ABCDE";
    int length = sizeof(str) - 1;

    if (length >= 6)
    {
        printf("strは6文字以上です。");
    }
    else if (length >= 3)
    {
        printf("strは3文字以上です。");
    }
    else
    {
        printf("strは3文字未満です。");
    }
    getchar();
}
strは3文字以上です。

char型配列による文字列には配列の終端にNULL文字が含まれるため、sizeof演算子は文字数+1の値を返すことに注意してください。
そのため、サンプルコードでは-1した値を変数lengthに代入しています。
(文字列の扱い方参照)

サンプルコードでは文字数の取得にsizeof演算子を使用していますが、sizeof演算子で得られるのは変数(配列)のバイト数です。
全角文字などのマルチバイト文字(2バイト以上の情報量の文字)を含む文字列では正しい文字数を得られません。
まだ正しい文字数を取得するための方法を説明していないので、ここではあえてsizeof演算子を用いています。

if(条件式){ 文 } [else if(条件式){ 文 }else{ 文 }]
条件式を満たす場合に文を実行する

if文は、条件式に指定された条件が成立するかどうかを判定し、成立する場合に{}内のコード(文)を実行します。
成立しなかった場合は次の条件(else if)を判定します。
いずれの条件も成立しなかった場合にはelseブロック内のコードが実行されます。

「else if」を増やすことで条件を何個でも追加できます。
「else if」や「else」は省略することもできます。
以下のコードはif文の条件が成立しないので、実行しても何も表示されません。


#include <stdio.h>

int main()
{
    char str[] = "ABCDE";
    int length = sizeof(str) - 1;

    if (length >= 6)
    {
        printf("strは6文字以上です。");
    }
    getchar();
}

if文は、上から順に条件判定をしていき、最初に条件を満たした条件のブロック内のみを実行します。
それ以降のelse if文、およびelse文のブロックは実行されません。


#include <stdio.h>

int main()
{
    char str[] = "ABCDEFG";
    int length = sizeof(str) - 1;
    if (length >= 6)
    {
        printf("strは6文字以上です。");
    }
    else if (length >= 3)
    {
        printf("strは3文字以上です。");
    }
    else
    {
        printf("strは3文字未満です。");
    }
    getchar();
}
strは6文字以上です。

上記のコードは最初の条件を満たすので、「strは6文字以上です。」と表示されます。
二つ目の条件も満たしますが、これは実行されません。

両方実行したい場合はif文を二つ(以上)に分けて書きます。


#include <stdio.h>

int main()
{
    char str[] = "ABCDEFG";
    int length = sizeof(str) - 1;
    if (length >= 6)
    {
        printf("strは6文字以上です。\n");
    }
    if (length >= 3)
    {
        printf("strは3文字以上です。\n");
    }
    if(length < 3)
    {
        printf("strは3文字未満です。\n");
    }
    getchar();
}
strは6文字以上です。
strは3文字以上です

関係演算子

条件の判定に使うのは関係演算子という記号です。
これは数学で使う記号と似ていますが、書き方がやや異なります。

a == b
aとbは等しい
a != b
aとbは等しくない
a > b
aはbより大きい
a >= b
aはbと等しいか、大きい
a < b
aはbより小さい
a <= b
aはbと等しいか、小さい

等号(=)はふたつ連続で書きます。
これがひとつだと代入になってしまい、正しく条件判定ができません。

!=はノットイコールといい、左右が等しくない場合に成立します。

大なりイコール、小なりイコールは数学では「≧」「≦」を使いますが、これは全角記号なので、半角の><=を組み合わせて使用します。

論理演算子

ひとつの条件式内で複数の条件判定を一度に行うには論理演算子を使用します。

a && b
aとbの両方が真の場合に真を返す
(論理積)
a || b
aまたはbが真の場合に真を返す
(論理和)
!a
aが偽の場合に真を返す
(論理否定)

は条件が成立、は条件が成立しない事を意味します。
それぞれTRUEFALSEともいいます。


#include <stdio.h>

int main()
{
    char str1[] = "ABCDE";
    char str2[] = "FGHIJ";
    int length1 = sizeof(str1) - 1;
    int length2 = sizeof(str2) - 1;

    if (length1 >= 3 && length2 >= 3)
    {
        printf("両方3文字以上");
    }
    else
    {
        printf("どちらか、または両方が3文字未満");
    }
    getchar();
}
両方3文字以上

文字列str1str2も三文字以上です。
条件式は両方とも成立するのでif文が実行されます。
もしどちらか一方でも条件が成立しない場合はelse文が実行されます。

否定は条件判定の真と偽を反転させます。


#include <stdio.h>

int main()
{
    char str[] = "AB";
    int length = sizeof(str) - 1;

    if (!(length >= 3))
    {
        printf("strは3文字未満");
    }
    else
    {
        printf("strは3文字以上");
    }
    getchar();
}

このコードのlength >= 3は成立しませんが、その判定結果を否定によって真偽を反転させています。
そのため最初のifブロックが実行されます。

!length >= 3と記述すると、変数lengthを否定することになるので注意してください。
これは!演算子と>=演算子とでは!演算子のほうが優先順位が高く、先に処理が行われるためです。

短絡評価(ショートサーキット)

論理演算子で複数の条件を同時に判定するとき、前半の条件式を判定するだけで条件式全体の条件を満たす/満たさないが決定できる場合があります。
例えば以下のような場合です。


//「0 == 1」は成立しないので
//後半の条件式が何であろうとこのif文は実行されない
if(0 == 1 && 1 == 1) {}

//「1 == 1」は成立するので
//後半の条件式が何であろうとこのif文は実行される
if(1 == 1 || 0 == 1) {}

前半だけで条件式全体の結果が判定できる場合、後半の条件判定を行う必要はありません。
このような場合、C言語では後半の条件式は実行されず処理がスキップされます。
これを短絡評価(ショートサーキット)といいます。

短絡評価はプログラムの高速化に繋がるので基本的には便利な機能です。
しかし「処理がスキップされることがある」ということを考慮しないと意図しない動作となる場合があります。


int Func()
{
	int ret = 0;
	//何らかの処理…
	return ret;
}

int main()
{
	int a, b;
	if((a = Func()) == 0 || (b = Func()) == 0) {
		printf("%d\n", a);
		printf("%d\n", b);
	}
}

上記コードでは、関数Funcの実行結果をそれぞれ変数に代入し、さらにその値を条件判定に使用しています。
(代入式を評価すると、代入された値が返されます)
このコードで最初の条件式(変数aへ代入した値と0との比較)が真になる場合、後半の条件式(変数bへ代入した値と0との比較)を実行する必要はなく、短絡評価となりif文が実行されます。
条件式の後半は完全にスキップされるので、二回目の関数Funcの実行はありませんし、その戻り値を変数bへ代入する処理もありません。
しかしif文は実行されるので、初期化していない変数bの値へのアクセスが行われてしまいます。

このようなコードはVisual Studioではコンパイル時エラーにしてくれますが、全てのコンパイラがそうとは限りません。
別の処理で変数を初期化(代入)していたり、そもそも変数を使わないような処理だとコンパイラはエラーを検出できません。

必ず実行されなければならない処理を、短絡評価を含む条件式に記述すると実行されない可能性があるので注意が必要です。


//初期化のための関数Init1とInit2は
//両方実行される前提でプログラムを作っている
//しかしこれだとInit2は実行されないかもしれない
if(Init1() == 0 && Init2() == 0) {}

数値の条件判定

C言語の条件式には数値を指定することもできます。


#include <stdio.h>

int main()
{
    if (0)
    {
        printf("0\n");
    }
    if (1)
    {
        printf("1\n");
    }
    if (-1)
    {
        printf("-1\n");
    }
    getchar();
}
1
-1

数値を条件判定すると、0は偽0以外は真と判断されます。
このサンプルコードのように数字をif文の条件に直接記述することはほとんどありませんが、変数の値をチェックして条件分岐することはよくあります。


#include <stdio.h>

int main()
{
    int number;

    //関数の実行結果を受け取る
    number = Func();
    
    if (number)
    {
        printf("0\n");
    }
    else
    {
        printf("0以外\n");
    }
    getchar();
}

条件式の評価値

条件式を評価した場合、真は1偽は0のint型の値が得られます。


#include <stdio.h>

int main()
{
    int cond1 = 0 == 1;
    int cond2 = 100 == 100;
    int cond3 = 1 < 0;
    int cond4 = !0;

    printf("%d\n", cond1);
    printf("%d\n", cond2);
    printf("%d\n", cond3);
    printf("%d\n", cond4);

    getchar();
}
0
1
0
1

ブロックの省略

if文やelse文で実行したい文が一行で済む場合はブロックの記述は省略できます。


if(num == 0)
{
    printf("Hello");
}
else
{
    printf("Bye");
}

//↓のように書ける

if(num == 0)
    printf("Hello");
else
    printf("Bye");

//改行も必須ではない
if(num == 0) printf("Hello");

if (num == 0) printf("Hello");
else printf("Bye");