- ベストアンサー
【C】fizzbuzzのトリッキーなコードについて
C言語でのfizzbuzz問題の回答を探していたら、以下のようなコードがありました。 #include <stdio.h> int main(void){ int i; for(i = 1 ; i <= 100 ; i++){ printf("%d \0Fizz \0FizzBuzz "+(i%5?(i%3?0:4):(i%3?14:10)),i); } printf("\n"); return 0; } (引用元:http://revilog.com/2010/08/c-fizzbuzz-printf.html) このコードについての質問です。 printf("%d \0Fizz \0FizzBuzz "+(i%5?(i%3?0:4):(i%3?14:10)),i); で、以下のことは理解しました。 ・\0で区切って文字列の終わりを作っておく ・+演算子でポインタ演算を行なっている ・三項演算子でポインタ演算する量を決めている ・+演算子によって指定したポインタから\0までの文字列を出力する ・Buzzを出力する際は、「FizzBuzz」の途中の「Buzz」を出力している わかっていないところは、 ・特殊文字(\0など)や「%d」は何バイトとして計算するのか ・数字以外を出力する際、%dによって桁数がずれ、変なところから出力されてしまうのではないか(でも実際はならない) です。 以上2点について回答よろしくお願いします。
- みんなの回答 (10)
- 専門家の回答
質問者が選んだベストアンサー
>普通に数えるとは、「\0」を1バイトとして数え、%dは代入後の数字で考えるということでよろしいでしょうか? "\0"については、そうですが "%d"の「代入後」ってどういう意味ですか? 例えば printf("%d", 123); とした場合、もしかしてprintf()に"123"という文字列が渡っていると思ってませんか? この場合printf()に引数として渡ってるのは"%d"と123です。 >すみません。いまいちよくわかりません。詳しく解説していただけないでしょうか。 上で説明してるので省略。 もっと詳細を知りたければprintf()関数の実装例などを読んでみてください。
その他の回答 (9)
- asuncion
- ベストアンサー率33% (2127/6289)
トリッキーなコードのトリックに、すっかり引っかかってしまったぜ。フフフ。
- asuncion
- ベストアンサー率33% (2127/6289)
>#8さん >#5 にしても #6 にしても, 「正確ではない」どころか「間違っている」と断ずるべきだと思います>#7. どうも失礼いたしました。 断じてください。
- Tacosan
- ベストアンサー率23% (3656/15482)
#5 にしても #6 にしても, 「正確ではない」どころか「間違っている」と断ずるべきだと思います>#7. 特に #5 の「回答」では, 質問者自身が「わかっていない」としている ・数字以外を出力する際、%dによって桁数がずれ、変なところから出力されてしまうのではないか(でも実際はならない) に対し余計に混乱させてしまうだけです. #6 にしても, あたかも「printf に渡す前に %d を書き換えている」かのような印象を与えてしまいます (これが間違いであることは #1/#3 で既に指摘されている通り). #1 および #3 の繰り返しになりますが, printf("%d", 123) という関数呼び出しにおいて printf に渡される引数は "%d" と 123 の 2つです. そして, 書式文字列にある変換指示 %d に対し「引数として渡されている (はずの) int の値」を出力するのは printf の仕事です. だから, 「数字以外を出力する際、%dによって桁数がずれ、変なところから出力されてしまう」 などということは起こりえません.
- m-take0220
- ベストアンサー率60% (477/782)
A No.6 それも正確ではないですね。 まず、"%d \0Fizz \0FizzBuzz "はこれらの文字列が格納された領域のポインタとして扱われます。 そこに、+(i%5?(i%3?0:4):(i%3?14:10))という式でポインタ操作を行っているので、iの値によってprintfに渡されるポインタの値自体が異なることになります。 printfに渡されたポインタが指す文字列に"%d"が含まれなければ、printfは引数の2番目に渡されたiを無視して処理します。
- asuncion
- ベストアンサー率33% (2127/6289)
先ほどの私の回答は、いささか正確さを欠いていましたね。 >printf("%d \0Fizz \0FizzBuzz "+(i%5?(i%3?0:4):(i%3?14:10)),i); printf()の第1引数は、あくまで "%d \0Fizz \0FizzBuzz "+(i%5?(i%3?0:4):(i%3?14:10)) ですね。で、第1引数の一部を構成している "%d \0Fizz \0FizzBuzz " ここに、 "1 \0Fizz \0FizzBuzz " "2 \0Fizz \0FizzBuzz " "3 \0Fizz \0FizzBuzz " ... "98 \0Fizz \0FizzBuzz " "99 \0Fizz \0FizzBuzz " "100 \0Fizz \0FizzBuzz " が順に入っていく、ということでありましょう。
- asuncion
- ベストアンサー率33% (2127/6289)
>printf("%d \0Fizz \0FizzBuzz "+(i%5?(i%3?0:4):(i%3?14:10)),i); printf()の第1引数には、 "1 \0Fizz \0FizzBuzz " "2 \0Fizz \0FizzBuzz " "3 \0Fizz \0FizzBuzz " ... "98 \0Fizz \0FizzBuzz " "99 \0Fizz \0FizzBuzz " "100 \0Fizz \0FizzBuzz " が、順に渡ります。 で、これらを、「実際にどう出力するか」を、 >+(i%5?(i%3?0:4):(i%3?14:10)) ここでコントロールしています。
- Gotthold
- ベストアンサー率47% (396/832)
#include <stdio.h> int main(void){ printf("%c\n", "%d \0Fizz \0FizzBuzz "[0]); return 0; } とか試せば、n文字目が何かは分かる。 > %dは代入後の数字で考えるということでよろしいでしょうか? %dはただの文字列です。 putsに渡してみれば理解できますか? #include <stdio.h> int main(void){ int i; char *format; for(i = 1 ; i <= 100 ; i++){ format = "%d \0Fizz \0FizzBuzz "+(i%5?(i%3?0:4):(i%3?14:10)); puts(format); //printf(format,i); //printf("\n"); } return 0; }
- Tacosan
- ベストアンサー率23% (3656/15482)
"%d" は何バイトですか?
- wormhole
- ベストアンサー率28% (1626/5665)
>・特殊文字(\0など)や「%d」は何バイトとして計算するのか 特殊文字でもなんでもないのでふつうに数えてください。 >・数字以外を出力する際、%dによって桁数がずれ、変なところから出力されてしまうのではないか(でも実際はならない) "%d"などの書式を解釈するのはprintf()系の関数です。 Cコンパイラが解釈するわけではありません。
補足
>特殊文字でもなんでもないのでふつうに数えてください。 普通に数えるとは、「\0」を1バイトとして数え、%dは代入後の数字で考えるということでよろしいでしょうか? >"%d"などの書式を解釈するのはprintf()系の関数です。 >Cコンパイラが解釈するわけではありません。 すみません。いまいちよくわかりません。詳しく解説していただけないでしょうか。
お礼
皆さん、たくさんの回答ありがとうございました。 すべての返信を書くのは大変なので、ここでまとめて返信させていただきます。 質問の件ですが、(多分)理解しました。 (1)メモリ上のどこかに"%d \0Fizz \0FizzBuzz "という文字列を作り、その先頭ポインタを (2)+演算子でずらしてprintf関数に渡し、 (3)printf関数内で、渡されたポインタを起点として%dなどがあったら整形し標準出力に出力 の順序で処理が行われているということでしょうか。 "%d"はprintf関数に渡す前はただの文字列であり、printf関数の中で"%d"を第二引数のものに変えている。 そうすると、%で1バイト、dで1バイトの合計2バイトとしていつも数えられるから、常に+4とか+10としても問題ないというわけですね。納得しました。 ありがとうございます。