時代遅れひとりFizzBuzz祭り C言語編

時代遅れひとり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;
}

まあしかしポインタがフラグとしての役割を兼ねている訳で、人によっては眉をひそめる書き方かもしれない。

*1:プロファイルを取って確かめるまでは気にする必要のない部分だけど、つい気になってしまう。

*2:でもポインタが無いと生きていけない。