時代遅れひとりFizzBuzz祭り、記念すべき第1回の言語はC言語。最も頻繁に使っている言語をチョイスしてみた。
C言語は仕事でメインに使用している言語。というか私の納品するコードの大半はC言語で、他言語からC言語のコードを生成する域には程遠い私は直接C言語でコーディングしているのだった、まる。
まあしかし、組込み関係でC言語というと色々と偏りがあるので、ANSI C89の範囲でも知らないことが結構ある。
前フリはここまでとして、まず普通に書いてみたコードから。関数化しているのは趣味で、特に意味は無い。
#include <assert.h> #include <stdio.h> #include <stdlib.h> static void pfizbuz(int n) { assert(n > 0); if (n % 15 == 0) (void) puts("FizzBuzz"); else if (n % 3 == 0) (void) puts("Fizz"); else if (n % 5 == 0) (void) puts("Buzz"); else (void) printf("%d\n", n); } int main(void) { int i; for (i = 1; i <= 100; ++i) { pfizbuz(i); } return EXIT_SUCCESS; }
うん、普通だ。if文に{}が無いけど、多分仕事で書く場合は{}をつけていると思う。
ところで、FizzBuzzでは3でも5でも割り切れる時に「FizzBuzz」と表示する。この言葉通りに解釈すると、
if (n%3 == 0 && n%5 == 0) (void) puts("FizzBuzz");
といったコードになるのだけど、この判定条件を自分の頭の中で展開して、
if (n % 15 == 0) (void) puts("FizzBuzz");
というコードにしている。
この点は、正直なところ賛否両論があるのではないかと思う。今回の条件では脳内で展開するのは別に難しくないのだけど、例えば条件が変更されたり追加されたりした場合はどうだろうか?
かといって「n%3 == 0 && n%5 == 0」という条件も、何というか微妙だ。最近のPCの資源は潤沢だとはいえ、何度も剰余を求めるのはちょっと気になる*1。
ということで別解を考えてみた。
#include <assert.h> #include <stdio.h> #include <stdlib.h> static void pfizbuz(int n) { int printed = 0; assert(n > 0); if (n % 3 == 0) { (void) printf("Fizz"); printed = 1; } if (n % 5 == 0) { (void) printf("Buzz"); printed = 1; } if (!printed) (void) printf("%d", n); (void) putchar('\n'); } int main(void) { int i; for (i = 1; i <= 100; ++i) { pfizbuz(i); } return EXIT_SUCCESS; }
別途フラグ変数を使用しているところが、個人的にスマートじゃないと思う。
ところでC言語にはあの悪名高きポインタという機能*2があるのだけど、ポインタを使うと気分的にほんの少しだけスマートな感じに書き直すことができる。
#include <assert.h> #include <stdio.h> #include <stdlib.h> static void pfizbuz(int n) { const char *msg = NULL; assert(n > 0); if (n % 3 == 0) msg = "Fizz"; if (n % 5 == 0) msg = (msg == NULL) ? "Buzz" : "FizzBuzz"; if (msg == NULL) (void) printf("%d\n", n); else (void) puts(msg); } int main(void) { int i; for (i = 1; i <= 100; ++i) { pfizbuz(i); } return EXIT_SUCCESS; }
まあしかしポインタがフラグとしての役割を兼ねている訳で、人によっては眉をひそめる書き方かもしれない。