代入式・繰り返し文・論理演算子・switch

はじめに

前回は型や条件分岐について勉強しました。簡単にプログラムで何を学んだのか振り返ってみましょうか。

#include <stdio.h>

int main(void){
    int ans;
    int a,b;
    printf("1か2を入力してください。:");
    scanf("%d",&ans);
    if(ans == 1){
        printf("足し算をします。\n");
        printf("一つ目の数字を入力してください。:");
        scanf("%d",&a);
        printf("二つ目の数字を入力してください。:")
        scanf("%d",&b);
        printf("足し算の結果は%dです\n",a+b);
    } else if(ans == 2){
        printf("引き算をします。\n");
        printf("一つ目の数字を入力してください。:");
        scanf("%d",&a);
        printf("二つ目の数字を入力してください。:")
        scanf("%d",&b);
        printf("引き算の結果は%dです\n",a-b);
    } else {
        printf("1か2を入力してください。\n")
    }
}

このプログラムは、実は前回の最後の練習問題の回答にもなっています。ちゃんとプログラムの意味を説明できますか?コメントを書いて、わからないところがないか調べるのもいいでしょう。

代入式について

新しい内容の前に、すこしだけ前回までの内容を補足しておきます。具体的には、代入式についてです。

代入式とは、以下のようなものです。

int a,b,c;
a = 3;
b = 4;
c = 4 * 3;
a = b * 3;

値を変数に代入するので、これらの式を代入式といいます。さて、ここで問題です。a、b、c、それぞれの値は何になるでしょうか?

答えは、a = 12,b=4,c = 12です。ちゃんと答えられましたか?二行目でaには3が代入されていますが、五行目でもう一度代入されているので結果としてaには b * 3 = 4 * 3 = 12 が代入されます。

さて、次はちょっと混乱するかもしれません。下のプログラムで、変数aに最終的に入っている値は何になるでしょうか?

int a = 3;
a = a * 3;

答えは9です。なんでだろう?とおもう人は、演算子の優先度を思い出してください。まず最初に、aには3が代入されます。次に、a = a * 3; では、まず優先度の高い=が評価され、aa * 3が代入されることになります。そして、a * 3を評価する時点では、aには3が代入されていますから、a * 3 = 3 * 3 = 9となります。よってaには9が代入されるのです。

これは少しわかりづらいことですから、頑張って理解しましょう。下の例を見て、共通項を見つけるような気持で理解するのもありです。

int a = 3;
a = a * a; // a * a = 3 * 3 = 9、なのでaには9が代入される。
int b = 4;
b = b - b; // b - b = 4 - 4 = 0、なのでbには4が代入される。
int c = 0;
c = c + b + a; // c + b + a = 0 + 9 + 0 = 9、よってcには9が代入される

わかりましたでしょうか?この辺は混乱のもとになりがちです。覚えて、わからなくなったら上のサンプルを見て自分のプログラムが正しいか、もう1回考えてみましょう。

+=、-=、*=、/=

次は代入演算子の中でも特別な演算子について勉強します。

int a = 20;
a += 30;

上のプログラムでは、aの値は50になります。理由はわかるでしょうか?+=というのは、左辺に、左辺の現在の値と右辺の値を足したものを代入する演算子です。演算子をバラさずに書くとこのような感じになります。

int a = 20;
a = a + 30;

*=-=/=も同じような意味になります。次のサンプルを見てください。

int a = 30;
a -= 2; // これは"a = a - 2;"と同じ。aは28になる。
int b = 40;
b *= 2; // これは"b = b * 2;"と同じ。bは80になる。
int c = 30;
c /= 5; // これは"c = c / 5;"と同じ。cは6となる。

++、--

代入式の中で、特殊な構文を教えます。

int i = 0;
i++;

i++は、i += 1と同じ意味を持ちます。上のプログラムの中ではiは1となるわけです。同じように、i--i -= 1と同じ意味を持ちます。

この2つの演算子を後置演算子と言います。後置演算子が特別に定義されているのは、よく使われるからです。次の繰り返しの章に入ると、どういうことかわかります。

まとめ

繰り返し文

さて、前回までで2つの数の足し算や引き算、それを少し応用すれば掛け算や割り算もできることがわかりました。では、次は累乗の計算について考えてみましょう。

まず一番簡単に、入力された数字を二乗して返すプログラムを考えてみましょう。

#include <stdio.h>

int main(void){
    int num;
    printf("二乗したい数字を入力してください:");
    scanf("%d",&num);
    printf("%dの二乗は%dです\n",num,num * num);
}

簡単ですね。このぐらいのプログラムであれば、五分ほどで書けるようになってると良いですね。

さて、二乗の計算は簡単でした。では、五乗の計算はどうでしょうか?

#include <stdio.h>

int main(void){
    int num;
    printf("5乗したい数字を入力してください:");
    scanf("%d",&num);
    printf("%dの5乗は%dです\n",num,num * num * num * num * num);
}

最後の行のnumが増えるだけですね。このプログラムを実行するときは、numの数が大きくなりすぎないように注意してください。今回は扱いませんが、オーバーフローという現象が起きます。

さて、このようなプログラムを書いていけば、累乗の計算はなんとかできそうだなということはわかりました。しかし、ここで1つ問題があります。「何乗するかもユーザーに決めてもらいたい」ときはどのようにすればいいのでしょう。

このときに必要なのが、繰り返し文です。

while文

繰り返し文はその名の通り、処理を繰り返すものです。まずはwhile文について勉強して行きます。

while文の構文はこのようになります。

while(繰り返す条件となる式){繰り返したい処理;}

if文のときと同じように、カッコの中には真か偽かの条件を入れます。ちょっとサンプルを見てみましょう。ユーザーが0を入力するまで「0を入力すると終了します。」と繰り返すプログラムです。

#include <stdio.h>

int main(void){
    int a = 1;
    while(a){
        printf("0を入力すると終了します。:");
        scanf("%d",&a);
    }
    return 0;
}

whileの中の条件はaですから、aが0以外であればwhile文の中の処理を繰り返します。aに0が代入されたら、whileの中の条件が偽となりますので、表示は終了します。

今まで学んだif文などと違うところは、while文は処理が繰り返されるということです。与えられた条件式が真にならない限り、中の処理はずっと繰り返されます。

上記のFlowChart

上記のFlowChart

これはフローチャートと言って、プログラムの流れを書く図です。これのように、条件式が偽にならない限りはずっと動き続けます。

#include <stdio.h>

int main(void){
    while(1){
        printf("終わらない!!!なんで???\n");
    }
    return 0;
}

つまり、こういうプログラムを書くと終わらなくなってしまうということです1。このプログラムが終わらないのは、条件式が1、つまりずっと真になっているからです。このプログラムは一生終わりません。もし実行してしまった人は、強制終了しましょう。場合によってはエラーを吐かれます。

while文を使うと、カウントのようなことも出来ます。これは0から9までカウントして終わるプログラムです。

#include <stdio.h>

int main(void){
    int i;
    i = 0;
    // < は数学と同じく、大きさの判定をする演算子です。
    // 左辺より右辺が大きければ真、そうでなければ偽となります。
    while(i < 10){
        printf("%d ",i);
        i++; // 後置演算子。 i = i + 1の意味です。
    }
    return 0;
}

iという変数を繰り返しごとに足していくと、最終的には10になって、while文の中の条件式と異なるのでwhile文の中を抜けます。このように、カウントをするプログラムを書くことができるのです。

もうちょっとサンプルを見てみましょう。これは、5乗をwhile文を使って計算するプログラムです。

#include <stdio.h>

int main(void){
    int input,answer = 1; // inputは入力用、answerは表示する用
    int count = 0; // カウンター。この変数を繰り返しごとに。
    printf("好きな数字を入力してください:");
    scanf("%d",&input); // inputに累乗したい数字を入力
    while(count < 5){
        answer *= input; // answer = answer * input;なので、繰り返しのたびにinputが掛け合わされて行きます。
        count++; // 繰り返されるたびにcounterが大きくなっていくので、四回繰り返すと4より大きくなってプログラムが終了する。
    }
    printf("%dです。\n",answer);
}

少し難しくなってしまいました。理解できるでしょうか?コメントをつけておきましたので、頑張って理解してみてください。

こんな風に、while文を使ってプログラムを組んでいきましょう。では練習問題です。

練習問題

  1. ユーザーに『累乗する値』と『何乗するか』どちらも入力させ、結果を表示するプログラムをwhile文を使って書きなさい。

ヒント : 上のプログラムを部分的に変えるだけでOK。上のプログラムで何乗するかを決めているところはどこか探してみよう。それをユーザーからの入力にできれば、問題のプログラムを作ることができる。

for

while文をかいていて、「繰り返しもっと簡単に書けないかな」と思いませんでしたか?思いましたね?あなたは優秀です。

繰り返す数が決まっている場合、while文よりも簡単に書ける記法があります。それはfor文です。for文の構文は次のようになっています。

for(式1;式2;式3) { 文;}

これは、while文の次の式と同じ意味になります。

式1;
while(式2){
    文;
    式3;
}

これだけだと意味がわからない人は、次のサンプルを見てください。これは0から9までカウントして終わるプログラムです。

#include <stdio.h>

int main(void){
    int i;
    for(i = 0;i < 10; i++){
        printf("%d ",i);
    }
}

このプログラム、どこかでみませんでしたか?whileでカウンタを作って見た時と同じプログラムですね。先程示したfor文とwhile文で、同じ意味になっていることを確認してみてください。

for文は、繰り返し処理の中でも回数が決まっているものに便利使うことが出来ます。たとえば、5乗を計算するプログラムをまたfor文で書き直してみましょう。

#include <stdio.h>

int main(void){
    int input, answer;  
    int count;
    answer = 1;
    printf("数字を入力してください。:");
    scanf("%d",&input);
    for(count = 0;count < 5;count++){
        answer *= input;
    }
    printf("%d\n",answer);
    return 0;
}

無事置き換えができました。やったね。

for文は、その書き方から多くの人が躓く部分です。はじめのうちはわからなくなったらwhile文との置き換えを参照するのもよいでしょう。

次に練習問題と行きたいところなんですが、for文の特殊な例があるので紹介しておきます。

#include <stdio.h>

int main(void){
    for(int i = 0; i < 10;i++){
        printf("%d ",i);
    }
}

for(int i = 0; i < 10;i++)となっています。今までとは違い、i = 0int i = 0に変わっていますね。上のプログラムのようにすると、予め宣言していなくてもfor文のカウンタ用に使う変数をfor文内で初期化できます。

上のfor文は、while文と正確な置き換えが出来ません。よくわからないな、という人はプログラムの意味が理解できればそれでいいです。

練習問題

  1. ユーザーに『累乗する値』と『何乗するか』どちらも入力させ、結果を表示するプログラムをfor文を使って書きなさい。

まとめ

論理演算子

次は論理演算子です。論理演算子というのは論理演算に使うための演算子です。説明になっていませんね。次のプログラムを見てください。入力された1つ目の数字が3で割り切れ、かつ入力された2つ目の数字が5で割り切れるときだけ文字を表示するプログラムです。

#include <stdio.h>

int main(void){
    int a,b;
    printf("一つ目の数字を入力してください。:");
    scanf("%d",&a);
    printf("二つ目の数字を入力してください。:");
    scanf("%d",&b);
    if(a % 3 == 0){ // 一つ目の数字を3で割ったあまりが0
        if(b % 5 == 0){ // 二つ目の数字を5で割ったあまりが0
            printf("よかったね。:");
        }
    }
}

ちょっと今までとは違って、if文の中にif文が出てきているので驚いてますか?でも心配しないでください。読んでいけば、ちゃんと「入力され1つ目の数字が3で割り切れ、かつ入力された2つ目の数字が5で割り切れるときだけ文字を表示するプログラム」になっていることがわかります。

さて、これを書きましたが、ちょっと野暮ったいですよね。if文の処理の中にif文しか書かれていないわけですし、この条件をまとめて1つのif文の中にかけたら便利ですよね。そんなとき使えるのが、論理演算子になります。

論理演算子は、より複雑な条件式を作るときにつかえます。上のプログラムは、論理演算子を使うとこんなふうになります。

#include <stdio.h>

int main(void){
    int a,b;
    printf("一つ目の数字を入力してください。:");
    scanf("%d",&a);
    printf("二つ目の数字を入力してください。:");
    scanf("%d",&b);
    // 一つ目の数字を3で割ったあまりが0
    // 二つ目の数字を5で割ったあまりが0
    if(a % 3 == 0 && b % 5 == 0){ 
        printf("よかったね。:");
    }
}

&&演算子はAND演算子といい、左辺式と右辺式がどちらも真であるときに真となります。どちらかが偽であれば、もう片方が真であっても偽となります。

論理演算子には次のようなものがあります。

演算子 演算子名 意味
a && b AND演算子 aとbがどちらも真のときのみ真
a || b OR演算子 aかbどちらかが真のときのみ真
!a NOT演算子 aが偽のとき真、aが真のとき偽
!0; // 0だけであれば偽だが、"!"が先頭についているので真となる。  !0 == 1.
int a = 30;
int b = 25;
a % 5 == 0 && b % 5 == 0; //真。
a % 5 == 0 || b % 5 == 0; //真。a && b が真であれば、a || bは必ず真になる。
a % 3 == 0 && b % 3 == 0; //偽。
a % 3 == 0 || b % 3 == 0; //真 

これらを使えると、プログラムをすっきりと書くことができるようになります。

練習問題

break,continue

break文とcontinue文というものについて学んでいきましょう。

break

breakとは、英語で切断するという意味です。その名の通り、ループから抜け出すのに使います。while文の最初の方でやった「0が入力されたら終了するプログラム」を思い出してみましょう。

#include <stdio.h>

int main(void){
    int a = 1;
    while(a){
        printf("0を入力すると終了します。:");
        scanf("%d",&a);
    }
    return 0;
}

このプログラムを、break文を使って書き換えるとこうなります。

#include <stdio.h>

int main(void){
    int a = 1;
    // 1だから基本は無限ループになってしまうが……
    while(1){
        printf("0を入力すると終了します。:");
        scanf("%d",&a);
        if(a == 0){ //aが0だったときに
            break; // ループを抜ける
        }
    }
    return 0;
}

break文を使うと、そのループを抜けて先にすすむことが出来ます。上のプログラムの場合、aが0だったときにbreak文によって6行目から12行目までのループを抜け、プログラムが終了します。

ちょっと複雑な例を見せると、こうなります。

#include <stdio.h>

int main(void){
    int count1 = 0;
    int count2 = 0;
    while(1){
        count2 = 0; // 毎回count2を0に
        while(1){
            count2++;
            if(count2 > 10){
                break;
            }
            printf("%d,%d",count1,count2);
        }
        count1++;
        if(count1 > 10){
            printf("終了します\n");
            break;
        }
    }
}

ずらーっと数字が出力されて終了したのではないでしょうか。whileが二重になっている場合(これを二重ループと言います)、breakでは1つのループしか抜けることが出来ません。なので、printf("終了します\n");の後のbreakで、やっと1つ目のwhile文を抜けることができるのです。

break文は非常に重宝します。

continue

次はcontinue文です。continue文は、ループ自体を抜けたいわけではないがあとの処理を一度スキップしたいという場合に使います。これもまた具体例を見てみましょう。次のプログラムは、0から9までカウントしていくなかで、2の倍数のときだけ表示しないプログラムです。

#include <stdio.h>

int main(void){
    int i;
    for(i = 0;i<10;i++){
        if(i % 2 == 0){
            continue;
        }
        printf("%d ",i);
    }
    return 0;
}

実行してみると奇数だけが表示されたのではないでしょうか。continue文は、ループの中で後の処理をスキップして次のループに戻るようなものです。ループの中で処理をスキップするときに使います。

continue文を使う場合、while文とfor文は前に示した形では置き換え不可能になっています。for文内でcontinueを使う場合、incrementは実行されます。ですが、while文でcontinueを使う場合、continue文の前にincrementを実行しておかないと無限ループになってしまいます。これはコードを書いてみるとすぐにわかります。

練習問題

  1. ユーザーに数字を入力してもらい、その値が5の倍数のときに終了するようなプログラムをbreak文を使って書きなさい。
  2. 0から20までカウントして、4の倍数以外のときにその数の二乗を表示するプログラムをcontinue文を使って書きなさい。

switch文

次はswitch文というものを勉強していきます。一番最初にやったプログラムを少し思い出してください。これです。

#include <stdio.h>

int main(void){
    int ans;
    int a,b;
    printf("1か2を入力してください。:");
    scanf("%d",&ans);
    if(ans == 1){
        printf("足し算をします。\n");
        printf("一つ目の数字を入力してください。:");
        scanf("%d",&a);
        printf("二つ目の数字を入力してください。:")
        scanf("%d",&b);
        printf("足し算の結果は%dです\n",a+b);
    } else if(ans == 2){
        printf("引き算をします。\n");
        printf("一つ目の数字を入力してください。:");
        scanf("%d",&a);
        printf("二つ目の数字を入力してください。:")
        scanf("%d",&b);
        printf("引き算の結果は%dです\n",a-b);
    } else {
        printf("1か2を入力してください。\n")
    }
}

さて、このプログラムに乗算と割り算の機能を追加してみましょう。こんな風になりますね。

#include <stdio.h>

int main(void){
    int ans;
    int a,b;
    printf("一つ目の数字を入力してください。:");
    scanf("%d",&a);
    printf("二つ目の数字を入力してください。:")
    scanf("%d",&b);
    printf("1か2か3か4を入力してください。:");
    scanf("%d",&ans);
    if(ans == 1){
        printf("足し算をします。\n");
        printf("足し算の結果は%dです\n",a+b);
    } else if(ans == 2){
        printf("引き算をします。\n");
        printf("引き算の結果は%dです\n",a-b);
    } else if(ans == 3){
        printf("掛け算をします。\n");
        printf("掛け算の結果は%dです\n",a*b);
    } else if(ans == 4){
        printf("割り算をします。\n");
        printf("割り算の結果は%fです\n",a/b);
    } else {
        printf("1か2か3か4を入力してください。\n")
    }
}

aとbの入力を前の方に持っていくことで、少しはスッキリしましたが、なんだかごちゃっとしていますね。これは、switch文を使って書くとこうなります。

#include <stdio.h>

int main(void){
    int ans;
    int a,b;
    printf("一つ目の数字を入力してください。:");
    scanf("%d",&a);
    printf("二つ目の数字を入力してください。:");
    scanf("%d",&b);
    printf("1か2か3か4を入力してください。:");
    scanf("%d",&ans);
        switch(ans){
        case 1:
            printf("足し算をします。\n");
            printf("足し算の結果は%dです\n",a+b);
            break;
        case 2:
            printf("引き算をします。\n");
            printf("引き算の結果は%dです\n",a-b);
            break;
        case 3:
            printf("掛け算をします。\n");
            printf("掛け算の結果は%dです\n",a*b);
            break;
        case 4:
            printf("割り算をします。\n");
            printf("割り算の結果は%fです\n",(double)a/(double)b);
            break;
        default:
            printf("1か2か3か4を入力してください。\n");
    }
}

なんだか見た目がスッキリしていませんか?スッキリしたんです。

switch文を使うと「この状態ではこの処理を、この状態ではこの処理を」という分岐をシンプルにかけます。if文でももちろん書けるのですが、switch文の方が見やすく、わかりやすいですね。

switch(value) {
    case 1: 
        //valueが1だったときの処理をここに書く
        break;
    case 2:
        // valueが2だったときの処理をここに書く
        break;
    default:
        // 上のcaseの中のどの値でもなかったとき(今回でいえば1,2どちらでもなかったときに)の処理をここに書く
        break;
}  

switch文の中は、変数でも式でも構いません。評価された値によってそれぞれのcaseの中に入っていきます。処理の最後にbreakをつけるのをわすれないでください。breakをつけるのを忘れると、その下に書いてある処理が全て実行されてしまいます。面倒ですね。

switch文は他の文に比べて感覚的に理解しやすいので、雰囲気で理解してもらっても構いません。

練習問題

  1. ユーザーに値を入力してもらい、その値が奇数か偶数かを表示するプログラムをswitch文で書きなさい。

  1. 真似するのはやめておきましょう