C言語ことはじめ 3日目: 制御構文 (条件分岐、ループ)

# <i class="fa fa-pencil fa-x"></i> はじめに

今回は制御構文についてまとめていこうかと思います。

今後コマンドラインからの文字入力が必要になってくるケースが多くなってきますので、文字の入力が必要な場合は、基本的にはstdio.hヘッダーから読み込める`getchar()`関数を使用していきたいと思います。( `getchar()`関数ですと、どのコンパイラでも対応しているため )

* `getchar()`関数についてのおさらい: アルファベット等の文字1文字を受け取って、intデータを戻り値とします。

```c
#include <stdio.h>

int main(void) {
  int str;

  str = getchar(); //コマンドラインでAと入力
  printf("%c\n", str); // Aと表示

  return 0;
}
```
C言語での情報の取り扱いは基本的に数字で行われます。getchar()は文字を扱う関数ですが、巧みに文字からASCIIコード(数字)、ASCIIコード(数字)から文字への相互変換が行われています。


# <i class="fa fa-pencil fa-x"></i> if、else、else if

条件分岐で最も使われるif〜else構文から扱っていきたいと思います。

```c
if(0)    printf("偽です"); //実行されません
if(1)    printf("真です"); //"真です"と表示
if('A')  printf("真です"); //"真です"と表示
```
if構文では、判定部に値が入ってさえすれば、その後の文が実行されます。

* `else`は`if`の判定部が全て偽だった時に実行されます。
* `else if`については、ifの条件を並列して複数並べたいときに使用します。

また`if`文、`else`文はネストする事も出来ますので、何通りもの条件分岐を簡単に作る事が出来ます。

```c
#include <stdio.h>

int main(void) {
  int answer;

  printf("(1 + 1) * 105の答えはなんでしょう？\n");
  scanf("%d", &answer);
  if(answer == 210) printf("正解です！\n");
  
  else{
    printf("最後のチャンスです.\n");
    printf("(1 + 1) * 105の答えはなんでしょう？\n");
    scanf("%d", &answer);

    if(answer == 210) printf("正解です。よくがんばりました。\n");
    else{
      printf("残念間違いです。英雄の館への扉は閉ざされました...\n");
    }
  }
  return 0;
}
```

# <i class="fa fa-pencil fa-x"></i> for ループ

forループでは、条件を指定して、それを指定した回数までループが実行されます。
C言語でのforループの特徴です。

* `for (初期設定部; 条件判定部; インクリメント部)`の三要素で構成
* forループでは、初期設定部はループが始まる前に一度だけ実行される
* 条件判定部が真のときは以下の処理が繰り返される
* インクリメント(++)部は毎回ループの末尾で繰り返される
* デクリメント(--)も出来る

```c
#include <stdio.h>

int main() {
  int answer;

  for (count = 1;count < 11; count++) {
    printf("%d + %dは？\n", count , count);
    scanf("%d", &answer);

    if(answer == count + count ) printf("正解!\n");
    else {
      printf("残念間違いです\n");
      printf("もう一度どうぞ\n");
      printf("%d + %dは？\n",count, count);
      scanf("%d", &answer);

      if(answer == count + count)printf("正解です！\n");
      else
        printf("残念間違いです。正解は%dです。\n", count + count);
    }
  }
  return 0;
}
```
`for`文を使用して、1~10までの`n + n`問題を表現するプログラムです。
条件分岐を組み合わせて、2度答えを間違えると答えを教えてくれるようになっていますね。

```c
#include <stdio.h>

int main() {
  int number;
  scanf("%d", &number);

  for( ;number > 0; number--){
    printf("デクリメントします%d", number);
  }
  return 0;
}
```
上記の用に、初期設定の部分を空欄にしておいてもforループを制御することができます。
３要素全て空欄の状態`for( ; ; )`も実行する事が出来ます。(永久ループにはなってしまいますが)このあたりの仕様は案外柔軟になっていますね。


# <i class="fa fa-pencil fa-x"></i> while ループ

whileループでは、forループと同じく条件を指定します。その条件が真である限り、ループが回ることになります。

またforとは条件の指定方法が異なります。

```c

#include <stdio.h>

int main() {
  char ch;

  printf("アルファベットを入力してください\n");

  while(ch != 'q') ch = getchar();
  printf("qが入力されました\n");
  
  return 0;
}
```
`q`の文字が入力されない限り、ずっとwhile内のループが回る事になります。
上記のように、常にコマンドラインで入力を受け付けられる状態にしておきたいときなどに、`getchar()`関数と共に用いると相性が良いでしょう。
**待機状態**を作成するのに最もよく使われている制御構造かも知れませんね。

# <i class="fa fa-pencil fa-x"></i> do~while ループ

```c

#include <stdio.h>

int main() {
  char ch;

    do {
      ch = getchar();
    } while (ch != 'q');

  printf("qが入力されました\n");
  return 0;
}
```

`do~while文`はwhile文の亜種のようなものです。
while文との違いは、**必ず処理が１度は実行される事**です。while内の条件が判定されるのは,`do`内の処理が一度実行されてからです！

# <i class="fa fa-pencil fa-x"></i> ループのネスト

```c

#include <stdio.h>

int main() {
  int answer, count,chances, right;

  for(count=1;count<11;count++){
    printf("%d + %dは？\n", count, count);
    scanf("%d", &answer);

    if(answer == count + count) printf("正解です！\n");
    else{
      printf("残念間違いです。もう一度どうぞ");

      right = 0;
      for(chances=0; chances <3 && !right; chances++){
        printf("%d + %dは？\n",count, count);
        scanf("%d", &answer);

        if(answer == count + count) {
          printf("正解です！\n");
          right = 1;
        }
      }
      if(!right)
        printf("正解は%dです\n", count + count);
    }
  }
  return 0;
}
```
`n + n`を3回間違えると回答が教えてもらえて、先に進むクイズです。
このようにループもネストさせることができるので、条件分岐をいっぱい生やすよりも簡潔に記載できることがあるかもしれませんね！


# <i class="fa fa-pencil fa-x"></i> switch

if文などで、条件分岐が増えてきたときなどに便利な制御構造です。

```c

#include <stdio.h>

int main(void) {
  int ch;

  do {
    printf("任意の文字を入力してください\n");
    ch = getchar();

    switch(ch){
      case 'a':
        printf("これはaです\n");
        break;
      case 'b':
        printf("これはbです\n");
        break;
      case 'c':
        printf("これはcです\n");
        break;
      default: printf("認識できない文字です\n");
        break;
      }
  }while(ch!='q');

  return 0;
}
```

入力を受け取ったアルファベットに応じて処理を切り替える事が出来ます。
条件毎に`break;`文を入れておかないと、フォールスルーが起きてしまうので注意しましょう！(該当した以下の条件全てが実行されてしまう)


# <i class="fa fa-pencil fa-x"></i> break

```c
#include <stdio.h>

int main() {
  int i;
  char ch;
  //2の倍数をNが入力されるまで表示する
  for(i=1;i<100;i++){
    if(!(i % 2)){
      printf("%d\n", i);
      printf("続行しますか？[Y/N]\n");
      ch = getchar();
      if(ch=='N') break;
    }
  }
  return 0;
}
```
`break`は任意の時点でループを抜けたいときに用いられます。
上記のコードでは、`N`が入力されればループを抜けるようになっています。
ネストされたループでは、一回のbreak抜けられるのは一段のループです。

上記で紹介したどのループでも使えるものと思われます。

# <i class="fa fa-star"></i> まとめ

今回はC言語での簡単な制御構文での例を見てみました。
どの言語でも使える事が多い構造なので、すんなり理解できるところが多かったです。

普段はRubyを使っているので、数字の0が偽になる所は驚きました。それが普通なんでしょうが...w

次はポインタ関連に言及していけたらいいなと考えています。

それではまた！