プログラミング C 06 - Soft Forum P.C. Club

while/switch/for

if文で分岐ができるようになりました. この後同じく分岐のswitch, 繰り返しのwhileとforをやります.

switch

switch文で広範囲な分岐を行うことができます.

#include <stdio.h>

int main(int argc, char **argv) {
  int ch;
  ch = getchar();
  switch (ch) {
    case 'a':
      printf("input: a\n");
      break;

    case 'b':
      printf("input: b\n");
      break;

    case 'c':
      printf("input: c\n");
      break;

    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
      printf("input: decimal %c\n", ch);
      break;
  }
  return 0;
}

getcharで文字を1字読み込み, switchで分岐しています.

case 'a'と書いたとき,

if (ch == 'a') {
  // caseの中身
}

が行われ, ch == 'a'がtrueならcase 'a':の中に入ります.

breakはswitch文を抜けるための文で, case 'a':の最後に書いています. これを書いていないと, case 'a':の最後でswitch文を抜けずに, case 'b'のほうへ突入します.(switchのfall through. bugの温床). このため, 特別な理由がないときはちゃんとbreakをつけるよう気をつけないといけません.

ただし, この面倒なことが役立つ場合があって, 上のcase '0':にはbreakがなく, case '1':に突入しています. これは, case '0':からcase '9':まで, どれとtrueになってもみんな

printf("input: decimal %c", ch);
break;

に辿り着くようになっています. breakしていないからです.

while

繰り替えし処理, whileです. これを使えば, 今まではずっと逐一書いてきた処理が, 繰り返しを見つけることによって簡潔かつ永続的に実行ができます.

while (exp)
  statement;

expがtrueである間, while文はstatementを実行します. 単純な話,

while (true) {
  printf("loop\n");
}

はみんな大好き無限loopです.

#include <stdio.h>

int main(int argc, char **argv) {
  int ch;
  while ((ch = getchar()) != EOF) {
    if (ch == 'Q' || ch == 'q') {
        printf("EXIT\n");
        break;
    } else if (ch != '\n') {
      printf("%c\n", ch);
    }
  }
  return 0;
}

getcharで読み込み, chに代入しています. getcharは読み込みが終了すると(終端文字に出会うと)EOFを返します. これはEnd Of Fileです.

if文の中で, chが'Q'か'q'であったときにprintf("EXIT\n")してbreakしています. このbreakは一番近いloopを抜けることができて, この場合はwhile文を抜け出し, 終了します.

それ以外だったら文字の表示です.

文字を入力するときにEnterを押していますね. これで実は入力文字に「改行」が入っています. \nです. ここでch != '\n'とすることで, 改行だけ無視しています.

カウンタ

whileで繰り返しを行う場合, カウンタという概念が重要になります.

n回繰り返すというのはどうすればいいのかということに対する一般的な解答です.


increment / decrement

インクリメントとデクリメントというものがあります.

#include <stdio.h>
int main(int argc, char **argv) {
  int a = 20, b, c;
  b = --a;
  c = a--;
  printf("a = %d\nb = %d\nc = %d\n", a, b, c);
  return 0;
}

デクリメントです. a = 18, b = 19, c = 19と表示されたら大丈夫です.

前置/後置デクリメントの2つがあります.

int a = 20, b, c;

この時点ではa = 20, b, cは不定です.

b = --a;

−−aが評価されて, まずaの値が−1されます. 19ですね. で, その19がbに代入されます.

c = a--;

a−−が評価されて, まずaの値そのままの19が返ります. で, その19がcに代入されます. そしてそれが終わった後, aの値は−1されて18になります.

このように後置の場合は評価時ではなくその後に−1されます.

カウンタ

以下のprogramの意味がわかれば大丈夫です.

#include <stdio.h>

int main(int argc, char **argv) {
  int n = 10;
  while (n--) {
    printf("%d\n", n);
  }
  return 0;
}

whileの中身がtrueかどうか, 確認するたびにnの数が−1されていきますね. すると正の数ならいずれは0になるはずです. 0はfalse評価されますので, 結果while文がとまります.

この場合, 9から0までの数, つまりloop自体は10回ったのを確認できると思います.

while (n--) {

で, n==10のときn−−は10を返すのでtrueです. 後置なので, それが終わったらnの値は9になっています. なのではじめに表示されるprintf("%d\n", n);は9でした.

これのnが1になったときを考えます.

while (n--) {

n−−でまず1が返るのでloopは続行ですね. でloop内でnは0になります.

で, 次のloopのときにn−−が0なのでwhile文が終了します.

これをもし前置でやるとどうなるでしょうか.

#include <stdio.h>

int main(int argc, char **argv) {
  int n = 10;
  while (--n) {
    printf("%d\n", n);
  }
  return 0;
}

9から1までしか表示されません. これはnが1のとき, −−nでは0になってしまい, n = 1の時点で打ち切られるからです.

ですので, whileで一般にn回loopするというときには,

#include <stdio.h>

int main(int argc, char **argv) {
  int n = 10;
  while (n--) {
    // 内容
  }
  return 0;
}

のようにします. for文が出ると将来的によりわかりやすい構文になります.

繰り返し処理を使う

ようやく分岐/繰り返しを覚えることで, 最低限のprogramを書く準備が整いました.

とりあえず, それっぽいのを書いてみましょう. Fibonacci数を求めるというprogrammerが大好きな話題です. (ことprogrammerがはじめに何か書くとき, Fibonacci数を求める/Hello Worldを表示する/FizzBuzzを解く のどれかをやる傾向があります...)

Fibonacci数とは,

n 番目のフィボナッチ数を Fn で表わすと F0 = 0, F1 = 1 Fn+2 = Fn + Fn+1 (n >= 0)フィボナッチ数 - Wikipedia

0, 1, 1, 2, 3, 5, 8, 13, 21 ...

前二つの数字を足したものが次の数字になるというあの数列です. 数学で昔やったかと.

n=0番目の値は0として0開始にします.

このn番目のFibonacci数を求めるというものです. どうでしょうか. やってみていただければ...

hint:

まず, 繰り返し処理を行うことはわかる.

また, n = 0 か n = 1のときはFibonacciの定義より0, 1とすぐに決まる.

よって繰り返しを行うのはn = 2からで, n = 2のとき1回処理を行うのだから, 繰り返し回数はn - 1になる.

そしてこの処理とは,

Fn = Fn-1 + Fn-2

を求めて, 保存しておくこと. 保存するためには, Fn-1のためのメモリ, Fn-2のためのメモリ, Fn-1 + Fn-2を一字保存しておくためのメモリの3つが繰り返し部分には必要になる.


解答

Soft Forum P.C. Club