
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点について回答よろしくお願いします。
No.3ベストアンサー
- 回答日時:
>普通に数えるとは、「\0」を1バイトとして数え、%dは代入後の数字で考えるということでよろしいでしょうか?
"\0"については、そうですが
"%d"の「代入後」ってどういう意味ですか?
例えば
printf("%d", 123);
とした場合、もしかしてprintf()に"123"という文字列が渡っていると思ってませんか?
この場合printf()に引数として渡ってるのは"%d"と123です。
>すみません。いまいちよくわかりません。詳しく解説していただけないでしょうか。
上で説明してるので省略。
もっと詳細を知りたければprintf()関数の実装例などを読んでみてください。
皆さん、たくさんの回答ありがとうございました。
すべての返信を書くのは大変なので、ここでまとめて返信させていただきます。
質問の件ですが、(多分)理解しました。
(1)メモリ上のどこかに"%d \0Fizz \0FizzBuzz "という文字列を作り、その先頭ポインタを
(2)+演算子でずらしてprintf関数に渡し、
(3)printf関数内で、渡されたポインタを起点として%dなどがあったら整形し標準出力に出力
の順序で処理が行われているということでしょうか。
"%d"はprintf関数に渡す前はただの文字列であり、printf関数の中で"%d"を第二引数のものに変えている。
そうすると、%で1バイト、dで1バイトの合計2バイトとしていつも数えられるから、常に+4とか+10としても問題ないというわけですね。納得しました。
ありがとうございます。
No.9
- 回答日時:
>#8さん
>#5 にしても #6 にしても, 「正確ではない」どころか「間違っている」と断ずるべきだと思います>#7.
どうも失礼いたしました。
断じてください。
No.8
- 回答日時:
#5 にしても #6 にしても, 「正確ではない」どころか「間違っている」と断ずるべきだと思います>#7.
特に #5 の「回答」では, 質問者自身が「わかっていない」としている
・数字以外を出力する際、%dによって桁数がずれ、変なところから出力されてしまうのではないか(でも実際はならない)
に対し余計に混乱させてしまうだけです. #6 にしても, あたかも「printf に渡す前に %d を書き換えている」かのような印象を与えてしまいます (これが間違いであることは #1/#3 で既に指摘されている通り).
#1 および #3 の繰り返しになりますが,
printf("%d", 123)
という関数呼び出しにおいて printf に渡される引数は "%d" と 123 の 2つです. そして, 書式文字列にある変換指示 %d に対し「引数として渡されている (はずの) int の値」を出力するのは printf の仕事です. だから,
「数字以外を出力する際、%dによって桁数がずれ、変なところから出力されてしまう」
などということは起こりえません.
No.7
- 回答日時:
A No.6
それも正確ではないですね。
まず、"%d \0Fizz \0FizzBuzz "はこれらの文字列が格納された領域のポインタとして扱われます。
そこに、+(i%5?(i%3?0:4):(i%3?14:10))という式でポインタ操作を行っているので、iの値によってprintfに渡されるポインタの値自体が異なることになります。
printfに渡されたポインタが指す文字列に"%d"が含まれなければ、printfは引数の2番目に渡されたiを無視して処理します。
No.6
- 回答日時:
先ほどの私の回答は、いささか正確さを欠いていましたね。
>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 "
が順に入っていく、ということでありましょう。
No.5
- 回答日時:
>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))
ここでコントロールしています。
No.4
- 回答日時:
#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;
}
No.1
- 回答日時:
>・特殊文字(\0など)や「%d」は何バイトとして計算するのか
特殊文字でもなんでもないのでふつうに数えてください。
>・数字以外を出力する際、%dによって桁数がずれ、変なところから出力されてしまうのではないか(でも実際はならない)
"%d"などの書式を解釈するのはprintf()系の関数です。
Cコンパイラが解釈するわけではありません。
この回答への補足
>特殊文字でもなんでもないのでふつうに数えてください。
普通に数えるとは、「\0」を1バイトとして数え、%dは代入後の数字で考えるということでよろしいでしょうか?
>"%d"などの書式を解釈するのはprintf()系の関数です。
>Cコンパイラが解釈するわけではありません。
すみません。いまいちよくわかりません。詳しく解説していただけないでしょうか。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# C言語 3 2022/10/04 15:07
- C言語・C++・C# 宣言する関数の形が決まっている状態で、 str1とstr2の文字列をこの順に引っ付けてstrに保存し 2 2022/05/30 18:21
- C言語・C++・C# C言語プログラム変更 2 2022/12/21 15:03
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- C言語・C++・C# c言語 プログラムのエラー 1 2023/02/11 20:31
- C言語・C++・C# C言語のエラーについて 2 2022/07/11 13:56
- C言語・C++・C# C言語: ポインタ 5 2022/06/01 08:33
- C言語・C++・C# C pointer? or... 2 2022/03/29 00:47
- C言語・C++・C# C言語の課題が出たのですが自力でやっても分かりませんでした。 要素数がnであるint型の配列v2の並 3 2022/11/19 17:41
- C言語・C++・C# 10個の実数に対する降順ソート結果を出力するプログラムを作りたいのですが、以下のプログラムをどう直せ 1 2022/07/09 22:16
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
プログラミングについて。 1つ...
-
gccを行ってもexeファイルが生...
-
c言語
-
visual studio 2022でのC#プロ...
-
C# DatagridviewにExcelシート...
-
mallocについて
-
C言語って古いですか?
-
C言語関数違いについて。
-
逆コンパイルと逆アセンブルの...
-
プログラムの実行時に'<'でリダ...
-
パソコン
-
CPUが16bitでも32bitOSでコンパ...
-
Python、プログラミングについ...
-
だれがとけるの?
-
バッチファイルで以下のような...
-
Notepad++の関数リスト表示の変...
-
VisualStudio2022でC言語プログ...
-
License='MIT' ってなんでmitな...
-
C言語 ストリームについて。
-
c言語でイベントフラグを使った...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
c言語
-
gccを行ってもexeファイルが生...
-
大量のデータを読み込んで表示...
-
visual studio 2022でのC#プロ...
-
C++でデスクトップGUIアプリ開...
-
【C言語】全角文字の配列を、全...
-
Windows Formアプリからコンソ...
-
VisualStudio2022でC言語プログ...
-
C#でログファイルにファイルパ...
-
C#でTreeViewのCheckBoxのサイ...
-
c#のTLS1.2での通信について
-
VisualStudioでC++クラスを追加...
-
C言語について。
-
int16_t の _t は何?
-
プログラマー達は何故、プログ...
-
逆コンパイルと逆アセンブルの...
-
C言語の関数のextern宣言
-
c言語でイベントフラグを使った...
-
C言語 関数、変数の宣言について
-
[C言語]fputsとfprintfの違い
おすすめ情報