if文を使わずにFizzBuzzをする
C
0
高専時代、C言語FizzBuzzコードゴルフ遊びをしてた時に後輩に教えてもらったやつ
for(int i = 1;i < 100;i++) {
printf("%d,%s\n",i,"\0____Fizz\0Buzz\0FizzBuzz" + (5 * !(i % 3) + 10 * !(i % 5)));
}
!が実質分岐の役割をしてなくもないが許してください
解説
for分で1から100まで回して、結果をprintfで出力するのは見ればわかるので割愛します。
まず"%d,%s\n" で整数と文字列を出してます。
問題はここですね。
"\0____Fizz\0Buzz\0FizzBuzz" + (5 * !(i % 3) + 10 * !(i % 5))
構造としては、文字列+数値ですが、C言語における文字列は先頭ポインタを指しています。
char *s = "Hello"; // s はアドレス100を指す
s + 0 // アドレス100 → "Hello"
s + 1 // アドレス101 → "ello"
s + 3 // アドレス103 → "lo"
ので、(5 * !(i % 3) + 10 * !(i % 5)) で3で割れるのか5で割れるのかでポインタに数値を足し、出したい文字列を出し分けています。
また、\0は終端文字を表すので、それ以降の文字は出力されません。
// 3で割れる時
// (5 * !(i % 3) + 10 * !(i % 5))) -> 5 * 1 + 10 * 0 -> 5
"\0____Fizz\0Buzz\0FizzBuzz" + 5 = "Fizz\0Buzz\0FizzBuzz" // Fizz が出力される
// 5で割れる時
// (5 * !(i % 3) + 10 * !(i % 5))) -> 5 * 0 + 10 * 1 -> 10
"\0____Fizz\0Buzz\0FizzBuzz" + 10 = "Buzz\0FizzBuzz" // Buzz が出力される
// 3, 5の両方で割れる時
// (5 * !(i % 3) + 10 * !(i % 5))) -> 5 * 1 + 10 * 1 -> 15
"\0____Fizz\0Buzz\0FizzBuzz" + 15 = "FizzBuzz" // FizzBuzz が出力される
// どちらでも割れない時
// (5 * !(i % 3) + 10 * !(i % 5))) -> 5 * 0 + 10 * 0 -> 0
"\0____Fizz\0Buzz\0FizzBuzz" + 0 = "\0____Fizz\0Buzz\0FizzBuzz" // 先頭が終端文字なので何も出力されない