ほぷしぃ

納得C言語!

[第7回]制御構文

制御構文


1.制御構文とは?

制御構文は、上から下へ流れるプログラムを途中で流れを分岐させたり、流れを繰り返したりすることができる構文を表します。
この制御構文を使うと・・・

・今までより複雑な処理をすることができる
・プログラムの流れを変えることができる

などと、今までと違ったプログラムを作成することができます。

A「制御構文って?」
B「判定して、どちらかの計算や出力を行うのか決めたり、同じ処理を繰り返し行うことが出来るようになるんだ」
A「どんな種類があるの?」
B「それはこれから見ていくよ。これを覚えれば、プログラムの流れを変えたり、より複雑な処理を行うことが出来たりなるよ」

と言うことで、これから制御構文の中身を見ていきましょう。


2.種類と使い方

制御構文の主な種類としてif文for文while文switch文の4パターンあります。

(1)if文

if文を使うと、分岐構造を作ることができます。
ゲームなどにもある「はい・いいえ」を選ぶとイベントやセリフが変わるアレと同じです。
if文の形式は以下の通りです。

パターン 書き方 意味
分岐構造(基本形)
if(条件式) {
    文1;
} else {
    文2;
}

条件式を満たすと文1を実行する
条件式を満たさないと文2を実行する
分岐構造(elseなし)
if(条件式) {
    文1;
}

条件式を満たすと文1を実行する
条件式を満たさないと何も行わない
多分岐構造
if(条件式1) {
    文1;
} else if(条件式2) {
    文2;
} else if(条件…

(中略)
} else if(条件式n) {
    文n;
} else {
    文x;
}

条件式1を満たすと文1を実行する
条件式1を満たさないで条件式2を満たすと文2を実行する

(中略)

条件式1〜n-1を満たさないで条件式nを満たすと文nを実行する
全ての条件を満たさないと文xを実行する
if文の入れ子
if(条件文1) {
    if(条件文2) {
        文1;
    } else {
        文2;
    }
} else {
    文3;
}

条件文1を満たし、さらに条件文2を満たすと文1を実行する
条件文1を満たし、条件文2を満たさないと文2を実行する
条件文1を満たさないと文3を実行する(ここは普通の分岐構造と一緒)


条件式とは分岐するための条件で変数や数値・文字列などの値、関係演算子論理演算子を用いて表します。
ここで関係演算子、論理演算子という新しい言葉が出てきました。
第3回で省略した演算子の一部ですが、これらは一体何でしょうか?

関係演算子

2つの値の大小を比較します。
条件を満たせば「真(true)」、条件を満たさなければ「偽(false)」となります。
関係演算子の形式は以下の通りです。

演算子意味
<a < baはbよりも小さい
>a > baはbよりも大きい
<=a <= baはbよりも小さい(a == bの条件も含む)
>=a >= baはbよりも大きい(a == bの条件も含む)
==a == baとbは等しい
!=a != baとbは等しくない

論理演算子

条件式を複数組み合わせたり条件を否定させたりすることができます。
論理演算子の形式は以下の通りです。

演算子意味
&&(and)a > 0 && b > 0aは0よりも大きいかつbは0よりも大きい
||(or)a > 0 || b > 0aは0よりも大きいまたはbは0よりも大きい
!(not)!aaではない


これらの条件式はif文以外でも使いますので必ず覚えましょう。
さて、長々と書いてしまいましたが、分岐構造(基本形)、多分岐構造、論理演算子を使った分岐構造の例を見て行きたいと思います。

例題1 分岐構造

#include <stdio.h>

int main()
{
    int a = 0, b = 0;
    printf("数値を2つ入力してください\n");
    printf("a=");
    scanf("%d", &a);
    printf("b=");
    scanf("%d", &b);

    if(a == b) {  //a, bが同じ数値なら以下の処理を行う
        printf("入力された数は同じです\n");
    } else {      //それ以外(a, bが違う数値)なら以下の処理を行う
        printf("入力された数は違います\n");
    }
    
    return 0;
}

結果

数値が同じ場合 数値が違う場合

(左)数値が同じ場合 (右)数値が違う場合

例題2 多分岐構造

#include <stdio.h>

int main()
{
    int a = 0, b = 0;
    printf("数値を2つ入力してください\n");
    printf("a=");
    scanf("%d", &a);
    printf("b=");
    scanf("%d", &b);

    if(a < b) {             //変数a, bの比較(aがbより小さければ)
        printf("bのほうが大きいです\n");
    } else if(a > b) {      //変数a, bの比較(aがbより大きければ)
        printf("aのほうが大きいです\n");
    } else {                //変数a, bの比較(a, bが同じ大きさならば)
        printf("同じ大きさです\n");
    }
    
    return 0;
}

結果

aの方が大きい場合 bの方が大きい場合 同じ場合

(左)aの方が大きい場合 (中央)bの方が大きい場合 (右)同じ場合

例題3 論理演算子を使った分岐構造

#include <stdio.h>

int main()
{
    int a = 0, b = 0;
    printf("数値を1つ入力してください\n");
    printf("a=");
    scanf("%d", &a);

    // 式「a<=0」と式「a>=100」が真ならば(1)の処理、それ以外なら(2)の処理
    if(a >= 0 && a <= 100) {
        printf("入力した数値は0〜100の間にあります\n");
    } else {                //変数a, bの比較(a, bが同じ大きさならば)
        printf("入力した数値は0〜100の間にありません\n");
    }
    
    return 0;
}

結果

aが0〜100の間にある場合 aが100以上の場合 aが0以下の場合

(左)aが0〜100の間にある場合 (中央)aが100以上の場合 (右)aが0以下の場合

if文を書くときのポイントは以下の通りです。

・if文を記述した後はインデント(字下げ機能)をしてプログラムを見やすくする
・文が単文(1行のみ)の場合は{ }を省略できる

インデントはVC++2005などのプログラムエディタを使っている場合は自動的にインデントが行われるので心配いりません。
インデントはプログラムを見やすくするために行うので特にインデントする必要はありませんが、他の人にプログラムを見せるときはインデントをしておきましょう。
{ }は単文の場合のみ省略することが出来ます。
条件文以外のプログラムと混同することもありますので単文でも{ }を付けた方がいいでしょう。
複文の場合は必ず{ }は必要となります。
このポイントはif文だけではなく、for文、while文、switch文でも同じなので必ず覚えよう。


(2)for文

for文を使うと、処理を反復(繰り返し)させる構造を作ることが出来ます。
for文の形式は以下の通りです。

for文の書き方

意味
 初期条件  for文を始めるときに初期化する変数と値を記述する。
基本的には継続条件となる変数を初期化する。
 継続条件  for文を継続させるための条件となる変数と値を記述する。
基本的には初期化式に記述した変数が使われる。
継続条件を満たしている限りはループを繰り返し、継続条件を満たしていない時はループをしない。
値変化 for文をループした時に変化する変数と値を記述する。
基本的には初期化式に記述した変数が使われる。

例文意味

for(i = 0; i < 10; i++) {
    文;
}

iが0からはじまり、iが10になるまで繰り
返し、ループするたびにiを1増やす


例文で使用されている「i++」はインクリメント演算子というものです。
意味にも書いてあるとおりiを1増やすという意味になります。
要するに「i = i + 1」を省略した形だと考えてください。
この演算子には他にも「i--」というデクリメント演算子というものもあり、こちらはiを1減らすという意味になります。
ここで、簡単にインクリメント/デクリメント演算子の形式を説明します。

演算演算子意味
インクリメント++ a++ aに1を加える
 ++a 
デクリメント-- a-- aから1を引く
 --a 


さて、ここで「aの前に演算子が書いてあるものとaの後ろに演算子が書いてあるものとは同じ意味」と捉えたかと思います。
確かに両方ともaに1加減するという意味なんですが、加減するタイミングが違います。

a++の場合
変数の前に演算子を書いた場合は式を評価する前に1を加えます。
++aの場合
変数の後に演算子を書いた場合は式を評価した後に1を加えます。

a--と--aの場合も同様です。
式を評価する前に計算することを前置演算、式を評価した後に計算することを後置演算といいます。
実際に例題4を書いてみて実感してみましょう。

例題4 インクリメント/デクリメント

#include <stdio.h>

int main()
{
    int a=0, b=0, c=0, d=0;

    printf("aの初期値:%d\n", a);
    printf("a++の値:%d\n", a++);    //式を評価したあとに+1
    printf("aの値:%d\n", a);

    printf("\n");

    printf("bの初期値:%d\n", b);
    printf("++bの値:%d\n", ++b);    //式を評価するまえに+1
    printf("bの値:%d\n", b);

    printf("\n");

    printf("cの初期値:%d\n", c);
    printf("c--の値:%d\n", c--);    //式を評価したあとに-1
    printf("cの値:%d\n", c);

    printf("\n");

    printf("dの初期値:%d\n", d);
    printf("--dの値:%d\n", --d);    //式を評価するまえに-1
    printf("dの値:%d\n", d);

    return 0;
}

printf()が多いのは気にしないで・・・とりあえず結果を見てみましょう!

結果

演算子の場所によって計算結果が違いますね

結果のように、演算子を変数の前と後で位置を変えると結果が変化しますね。

またまた前置きが長くなってしまいました・・・for文もif文と同じように例題を書いていきましょう!

例題5 for文で平均を求める

#include <stdio.h>

int main()
{
    int n = 0 ,s = 0 ,sum = 0, avg = 0;      //変数の宣言と初期化
    printf("数値を20個入力してください\n");

    for(n=1; n<=20; n++)            //nに1を代入、nが20になるまで、nに1を足す
    {
        printf("%d個目の数値を入力してください=",n);
        scanf("%d",&s);

        //「sum = sum + s」で入力された数値sとsum(0)を足し結果をsumに代入
        //これをすることにより今まで入力された数値の合計をsum変数内に格納できる
        sum = sum + s;

    }
    avg = sum / 20; //数値20個の平均を求める計算式
    printf("平均値%d",avg);
    return 0;
}

結果

20回繰り返しました

これをfor文を使わないで書いたらすごい行数になりそうですね。
暇な人はfor文を使わないで書いてみて、for文のありがたさを実感してみるのもいいでしょう。


(3)while文

while文を使うと、処理を反復(繰り返し)させる構造を作ることが出来ます。
「それではfor文と全く同じじゃないか!」と思っている人も少なくともいるでしょう。
一般的にfor文は「指定した回数分だけ処理を繰り返す」、while文は「指定した条件を満たすまで処理を繰り返す」と言う意味で、for文とwhile文は似ているようで定義されている意味は違います。

for文とwhile文の違いを簡単に理解してもらったところで、while文の形式は以下の通りです。

while文の書き方

継続条件があらかじめ満たしていない場合はwhile文の命令は実行されません。

例文意味

while(i < 10) {
    文;
}

iが10になるまでループを繰り返す


それでは、for文と一緒の使い方をするためにはどのようにすればいいのでしょうか?
初期化式をwhile文が始まる前に、値変化をループの最後に記述すればfor文と全く同じになります。

両方とも同じ意味

for文を使ったとき while文を使ったとき
for(i = 0; i < 10; i++) {
    文;
}

i = 0;
while(i < 10) {
    文;
    i++;
}



今回は短い説明でしたね。それでは、例題を行ってみましょう。

例題6 例題5をwhile()文で・・・

#include <stdio.h>

int main()
{
    int n=1, s=0, sum=0, avg=0;

    printf("数値を20個入力してください\n");

    while(n<=20)  //()の中が真の間繰り返す
    {
        printf("%d回目の入力=",n);  //nは1周するごとに+1されていく
        scanf("%d",&s);
        sum += s;    //sum = sum + sという意味(sum + sを計算し、sumに代入)
        n++;         //while(〜)の条件になるまでnに1を足す

    }

    avg=sum/20;      //平均値を求める式
    printf("平均値=%d\n",avg);

    return 0;
}

結果

動きはforと同じです

例題5と同じ結果になりましたね。
余談ですが、for文とwhile文、処理速度が速いのはどちらでしょうか?
昔、while文のほうが速いと聞いたことがあるのですがどうでしょう?
暇があれば書いてみたいと思います。


(4)switch文

switch文を使うと、多分岐構造を作ることが出来ます。
if〜else if〜elseを使うより簡単に多分岐構造を作れます。
switch文の形式は以下の通りです。

switch文の書き方

意味
 条件式  条件を比較するための式、基本的に変数を書く
 定数  条件に使われる定数、基本的に整数や文字を書く


switch文では条件式を使って分岐させ、定数と条件が等しくなるとcase以下の処理を実行し、breakを見つけるとswitch文から抜け出します。
breakを書き忘れると、次のcase条件まで実行してしまうので、breakの書き忘れには十分注意が必要です。
条件式・定数はともに整数と文字のみ使え、小数などの実数や、文字列は使用できません。

それでは、例によって例題を行いましょう。

例題7 switch文で月の日数を表示させよう!

#include <stdio.h>

int main()
{
    int i = 0;
    printf("1〜12の数値の内1つ数値を入力してください\n");
    scanf("%d",&i);

    //switch(i)にはデフォルトだと0が入っている
    switch(i)
    {
    case 1:    //1月が入力された場合
        printf("1月は31日です\n");
        break;
    case 2:    //2月が入力された場合
        printf("2月は28日です\n");
        break;
    case 3:    //3月が入力された場合
        printf("3月は31日です\n");
        break;
    case 4:    //4月が入力された場合
        printf("4月は30日です\n");
        break;
    case 5:    //5月が入力された場合
        printf("5月は31日です\n");
        break;
    case 6:    //6月が入力された場合
        printf("6月は30日です\n");
        break;
    case 7:    //7月が入力された場合
        printf("7月は31日です\n");
        break;
    case 8:    //8月が入力された場合
        printf("8月は31日です\n");
        break;
    case 9:    //9月が入力された場合
        printf("9月は30日です\n");
        break;
    case 10:   //10月が入力された場合
        printf("10月は31日です\n");
        break;
    case 11:   //11月が入力された場合
        printf("11月は30日です\n");
        break;
    case 12:   //12月が入力された場合
        printf("12月は31日です\n");
        break;
    default:   //1〜12の数値以外が入力された場合に出力される
        printf("数値が間違っています\n");
        break;
    }

    return 0;
}

結果

12と入力した場合 8と入力した場合

(左)12と入力した場合 (右)8と入力した場合

日数が表示されましたね!ちなみに、うるう年は考えていません。
Cがある程度できるようになれば、うるう年の計算もできるようになります。


3.break/continue

switch文のところでbreakというのが何回も登場しました。
switch文での意味は「switch文から抜け出す」という意味でしたね。
breakはswitch文以外にもfor文やwhile文のループの中でも使うことが出来ます。
この時もbreakは「for文やwhile文のループから抜け出す」という意味を持っています。
その中でもfor文やwhile文のbreakは無限ループでよく使用されます。
for文やwhile文などで継続条件を常に満たすようにすると無限ループになります。

breakとセットに覚えてほしいのがcontinueです。
continueはfor文やwhile文などのループ処理をスキップさせるに用います。
breakとは違い、continueはスキップした後は、ループの先頭に戻ります。
breakとcontinueの使い方を間違いないようにしてください。

例題8 無限ループ while文で無限ループを作ってみましょう

#include <stdio.h>

int main()
{
    int i=0, n=0, sum=0;
    printf("数値を足していきます(0を入力すると計算を終了します)\n");

    while(1)      //真の間以下の処理を繰り返す
    {
        printf("足す数を入力してください\n");
        scanf("%d",&i);
        sum += i;    //入力した数値を足してゆく式 ( sum = sum + i ) と同じ意味

        printf("只今の合計%d\n",sum);

        if(i == 0)    //i==0の場合ループから抜ける
        {
            break;
        }
    }
    return 0;
}

結果

0を入力したら終わりました

while文の()の中に1と書くと、常に「真」の状態となり、{ }の中を無限に繰り返します。
例題8ではユーザが「0」を入力したときにbreak文でwhile文から抜け出しています。


4.練習問題

(1)

数値を入力して、それらが正か負かのどちらか判断するプログラムを書いてみよう。
(注意)0は正数とします

出力結果 出力結果

(左)負数が入力された場合 (右)0を含む正数が入力された場合

(2)

数値を入力し、1から入力された数の合計を求めてみよう。

出力結果

(3)

第2問のプログラムをwhile文を使って書いてみよう。

出力結果

(4)

コーヒー100円、コーラ120円、紅茶105円、野菜ジュース130円とします。コーヒー→1、コーラ→2、紅茶→3、野菜ジュース→4として、それぞれの数値が入力されたら種類と値段を表示するプログラムを書いてみよう。

出力結果 出力結果

(左)コーラを選択した場合 (右)選択肢以外の数値を入力した場合


[第6回]関数 ページのトップ 解答