natechoe.dev The blog Contact info Other links The github repo

A neat fizzbuzz implementation

I'll start with the code so that people who already understand fizzbuzz can read it, exhale a bit of air out of their nose, go "neat", and move on.

#include <stdio.h>
int main() {
	for (int i = 1; i <= 100; ++i) {
		switch ((i % 3 == 0) << 1 | (i % 5 == 0)) {
		case 0: printf("%d\n", i); break;
		case 1: puts("buzz"); break;
		case 2: puts("fizz"); break;
		case 3: puts("fizzbuzz"); break;
		}
	}
	return 0;
}

Fizzbuzz is a classic programming interview problem. It's based on a game, which goes like this:

  1. Players take turns counting. Player 1 says "one", player 2 says "two", and so on.
  2. For multiples of three, instead of saying the number, players say the word "fizz".
  3. For multiples of five, instead of saying the number, players say the word "buzz".
  4. For multiples of both three and five, instead of saying the number, players say the word "fizzbuzz".

So in this game, players would say 1, 2, fizz, 4, buzz, fizz, 7, 8, fizz, buzz, 11, fizz, 13, 14, fizzbuzz, and so on.

Playing fizzbuzz is a classic interview problem. A candidate might start by writing a program to print numbers without any special rules, like this:

#include <stdio.h>
int main() {
	for (int i = 1; i <= 100; ++i) {
		printf("%d\n", i);
	}
	return 0;
}

Then the candidate might realize that they could impress the interviewer by writing a subroutine, like this:

#include <stdio.h>

void print_fizzbuzz(int n) {
	printf("%d\n", n);
}

int main() {
	for (int i = 1; i <= 100; ++i) {
		print_fizzbuzz(i);
	}
	return 0;
}

Next they might implement the rules for 3 and 5 using the modulo operator.

#include <stdio.h>

void print_fizzbuzz(int n) {
	if (n % 3 == 0) {
		puts("fizz");
	}
	else if (n % 5 == 0) {
		puts("buzz");
	}
	else {
		printf("%d\n", n);
	}
}

int main() {
	for (int i = 1; i <= 100; ++i) {
		print_fizzbuzz(i);
	}
	return 0;
}

Now they want to implement the "fizzbuzz" rule. They suddenly realize that they have to put this rule in the beginning of this if else chain so that it actually has a chance to execute.

#include <stdio.h>

void print_fizzbuzz(int n) {
	if (n % 3 == 0 && n % 5 == 0) {
		puts("fizzbuzz");
	}
	else if (n % 3 == 0) {
		puts("fizz");
	}
	else if (n % 5 == 0) {
		puts("buzz");
	}
	else {
		printf("%d\n", n);
	}
}

int main() {
	for (int i = 1; i <= 100; ++i) {
		print_fizzbuzz(i);
	}
	return 0;
}

Then, the interviewer asks the candidate to extend the game, so that you say "bash" for multiples of 7.

The interviewee looks at their code in shame. Extending this out would be an absolute pain. They also realize that the print_fizzbuzz function is pretty much useless because it always outputs to standard output, so it's really only suited to this one specific task. They tear it down and begin rewriting it like this:

Ideally, the print_fizzbuzz function actually returns a string, but in C it's actually suprisingly hard to just return a dynamically generated string, so for brevity I've made the code output to a file.
#include <stdio.h>

void print_fizzbuzz(int n, FILE *out) {
	if (n % 3 == 0) {
		fputs("fizz", out);
	}
	if (n % 5 == 0) {
		fputs("buzz", out);
	}
	if (n % 7 == 0) {
		fputs("bash", out);
	}
	/* TODO: Print regular numbers??? */
	fputc('\n', out);
}

int main() {
	for (int i = 1; i <= 100; ++i) {
		print_fizzbuzz(i, stdout);
	}
	return 0;
}

Now they realize that they have to print regular numbers, so they add a boolean flag.

#include <stdio.h>
#include <stdbool.h>

void print_fizzbuzz(int n, FILE *out) {
	bool print_number = true;
	if (n % 3 == 0) {
		fputs("fizz", out);
		print_number = false;
	}
	if (n % 5 == 0) {
		fputs("buzz", out);
		print_number = false;
	}
	if (n % 7 == 0) {
		fputs("bash", out);
		print_number = false;
	}
	if (print_number) {
		fprintf(out, "%d", n);
	}
	fputc('\n', out);
}

int main() {
	for (int i = 1; i <= 100; ++i) {
		print_fizzbuzz(i, stdout);
	}
	return 0;
}

Now we've got a bunch of duplicate code for each condition, so the candidate separates them out.

#include <stdio.h>
#include <stdbool.h>

/* I love X-macros */
#define FIZZBUZZ_CONDITIONS \
	X(3, "fizz") \
	X(5, "buzz") \
	X(7, "bash")

void print_fizzbuzz(int n, FILE *out) {
	bool print_number = true;
#define X(modulus, string) \
	if (n % modulus == 0) { \
		fputs(string, out); \
		print_number = false; \
	}
	FIZZBUZZ_CONDITIONS
#undef X
	if (print_number) {
		fprintf(out, "%d", n);
	}
	fputc('\n', out);
}

#undef FIZZBUZZ_CONDITIONS

int main() {
	for (int i = 1; i <= 100; ++i) {
		print_fizzbuzz(i, stdout);
	}
	return 0;
}

If you actually wrote this code in an interview, the interviewer would probably look at you like you've just committed a violent crime. X-macros are kind of like regex; they're really powerful, but whenever you use them you feel like you're practicing the dark arts.

Anyways, then the interviewer might ask you to capitalize the first letter of each line. This leads to a problem: we can print "Fizz", we can print "Buzz", and we can print "FizzBuzz", but we can't print "Fizzbuzz".

We can reuse the print_number variable to see if we're at the beginning of the line and extend our X-macro to accept a lowercase and uppercase form of our letters, though, like this:

#include <stdio.h>
#include <stdbool.h>

/* I love X-macros */
#define FIZZBUZZ_CONDITIONS \
	X(3, "fizz", "Fizz") \
	X(5, "buzz", "Buzz") \
	X(7, "bash", "Bash")

void print_fizzbuzz(int n, FILE *out) {
	bool print_number = true;
#define X(modulus, lower, upper) \
	if (n % modulus == 0) { \
		if (print_number) { \
			fputs(upper, out); \
		} \
		else { \
			fputs(lower, out); \
		} \
		print_number = false; \
	}
	FIZZBUZZ_CONDITIONS
#undef X
	if (print_number) {
		fprintf(out, "%d", n);
	}
	fputc('\n', out);
}

#undef FIZZBUZZ_CONDITIONS

int main() {
	for (int i = 1; i <= 100; ++i) {
		print_fizzbuzz(i, stdout);
	}
	return 0;
}
There are definitely cleaner ways to do this in other languages, but this is the cleanest thing I could think of that doesn't use dynamic memory allocation or assume a certain string length limit.

Now the interviewer asks you to print "Buzzfizz" instead of "Fizzbuzz", but to keep printing "Fizzbuzzbash" whenever that shows up.

That's not too bad, we can just create a special case in our function.

#include <stdio.h>
#include <stdbool.h>

/* I love X-macros */
#define FIZZBUZZ_CONDITIONS \
	X(3, "fizz", "Fizz") \
	X(5, "buzz", "Buzz") \
	X(7, "bash", "Bash")

void print_fizzbuzz(int n, FILE *out) {
	bool print_number = true;
	if (n % 3 == 0 && n % 5 == 0) {
		fputs("Buzzfizz\n", out);
		return;
	}
#define X(modulus, lower, upper) \
	if (n % modulus == 0) { \
		if (print_number) { \
			fputs(upper, out); \
		} \
		else { \
			fputs(lower, out); \
		} \
		print_number = false; \
	}
	FIZZBUZZ_CONDITIONS
#undef X
	if (print_number) {
		fprintf(out, "%d", n);
	}
	fputc('\n', out);
}

#undef FIZZBUZZ_CONDITIONS

int main() {
	for (int i = 1; i <= 100; ++i) {
		print_fizzbuzz(i, stdout);
	}
	return 0;
}

Then the interviewer gives a bunch more edge cases. Eventually, the interviewer just hands you a table, and says "This is what we want.

Multiple of 3 Multiple of 5 Multiple of 7 Output
No No No The number itself
Yes No No "Fizz"
No Yes No "Buzz"
Yes Yes No "Banana"
No No Yes "Bash"
Yes No Yes "Bonanza"

And so on, for every single case. This is the most generalized form of fizzbuzz that you can possibly get, and can only be solved with the most generalized code that you can possibly write:

#include <stdio.h>
int main() {
	for (int i = 1; i <= 100; ++i) {
		switch ((i % 3 == 0) << 1 | (i % 5 == 0)) {
		case 0: printf("%d\n", i); break;
		case 1: puts("buzz"); break;
		case 2: puts("fizz"); break;
		case 3: puts("fizzbuzz"); break;
		}
	}
	return 0;
}

Just use bitmaps to assign each case a number, and manually handle each case in a switch statement.