No.2
- 回答日時:
unixは1を表すんですね。
知りませんでした。printf()が一つ呼ばれているだけですから、その引数の意味を示せばよいのだと思いますが、
まず、unix["\021%six\012\0"]ですが、アドレス1を先頭として、文字列"\021%six\012\0"の
アドレス分だけプラスした文字のアドレス・・・ということは、とりも直さず
文字列"\021%six\012\0"の2文字目のアドレスということになります。(先頭はゼロですから。)
で、\012は\nのことですから、この第一引数は"%six\n"と同じことになります。
第二引数は、同じ理屈で"have"の二文字目ですが、こちらはアドレスではありませんので、
'a'という値、つまり0x61になります。0x61に"fun"のアドレスを加え、0x61を引くということは
つまり"fun"の2文字目のアドレスと同じことですから、第二引数は"un"です。
つまり、このプログラムは
main(){printf"%six\n","un");}
ということです。
No.3
- 回答日時:
配列の解釈と文字とコードの変換が頭に浮かぶかどうかが問われているわけですね。
"abc"[1] → *("abc" + 1)
1["abc"] → *(1 + "abc")
このあたりの概念は馴染みずらい所かもしれない。
No.4ベストアンサー
- 回答日時:
Jizouと申します。
順に考えていきます。
main(){ printf(&unix["\021%six\012\0"],(unix)["have"]+"fun"-0x60);}
(ヒント:#define unix 1)
== Step 1: =========================================================
#defineマクロはソースコードのコンパイルが行われる前に実行されます
から、ソースコード内の unix という文字列はすべて 1 という文字に
置き換えられます。置き換えたものが次のソースです。
main(){ printf(&1["\021%six\012\0"],(1)["have"]+"fun"-0x60);}
== Step 2: =========================================================
次に "\021%six\012\0" を解釈します。
文字列中の \0nn という表現は nn を8進数として解釈しますので、\021 は
10進数で 17( = 8 * 2 + 1)、16進数で 11 を示す値となります。同じよ
うに \012 は 10進数で 10( = 8 * 1 + 2 )、16進数で 0a を示す値とな
ります。\0 は 0(ゼロ)です。
\021 == 17 == \0x11
\012 == 10 == \0x0a
ASCIIコード表で 17 が何を表すか分かりませんが、10 は「改行」を表しま
すので '\n' と同じ意味です。(改行と '\n' が厳密に同じかどうかはちょ
っと参考書をひっくり返さなければ分かりませんが、今回のケースでは同じ
と考えても問題ないと思います)
文字列の最後はもともと終端コードとして '\0' が1個入っていますので、
このソースの場合には '\0' コードが2個入ることになります。
結局 "\021%six\012\0" は "\0x11%six\n" と同じ意味になります。
main(){ printf(&1["\0x11%six\n"],(1)["have"]+"fun"-0x60);}
== Step 3: =========================================================
次が最も難解な部分だと思いますが、&1["\0x11%six\n"] を解釈します。
これは良く使う形としては answer_text[3] という形と同じです。
C言語では文字列変数を char answer_text[100]; のように定義すると
answer_text というラベルは宣言した文字列の先頭アドレスを表すラベルと
して扱われます。
この文字列の4文字目を取り出す場合に answer_text[3] という書き方をし
ますが、これは内部的には次のような形に変換される規則になっています。
answer_text[3] ===> *( answer_text + 3 )
answer_text というアドレスに 3 を加えて、そのアドレスから1文字取り
出すというわけです。
ところがこの変換式は answer_text の位置と 3 の位置に何を書いても上記
のように変換される規則になっています。ですので answer_text と 3 の位
置を入れ替えてもエラーなくコンパイルできてしまい、意味も同じになりま
す。
3[answer_text] ===> *( 3 + answer_text )
ですので 1["\0x11%six\n"] はカギ括弧の中と外を入れ替えた "\0x11%six\n"[1]
と同じ物なのです。この「文字列の後ろにインデックスを添える」という形
も普通は使いませんが、文字列変数も文字列も同じようなものだと思えばこ
れは「その文字列の2文字目を示す」ものだということがお分かりいただけ
ると思います。
1["\0x11%six\n"] ===> 文字列 "\0x11%six\n" の2文字目を示す。
今回のケースでは先頭にアンパサント(&)が付いていますので、さらに「そ
のアドレスを示す」ということになります。つまり
&1["\0x11%six\n"]
===> 文字列 "\0x11%six\n" の2文字目の先頭アドレスを示す。
===> "%six\n"
ということになります。(要するに先頭の1文字 '\0x11' を読み飛ばす)
main(){ printf( "%six\n", (1)["have"]+"fun"-0x60);}
== Step 4: =========================================================
お次は (1)["have"] です。
ここで (1) は 1 と同じですので実質的には 1["have"] と同じです。
これは上でやった内容と同じですので次のようになります。
(1)["have"] ===> 1["have"] ===> "have"[1]
これは「"have" の2文字目」という意味になりますので、'a' ということ
になります。
main(){ printf( "%six\n", 'a'+"fun"-0x60);}
== Step 5: =========================================================
その次は 'a'+"fun"-0x60 です。
文字 'a' は16進数では 61 ですので C言語の表記では \0x61 となります。
さてその次の "fun" ですが、ソースコード中の文字列は式の中では「その文
字列の先頭アドレス」を示す値となります。
したがってこの式は次のように解釈されます。
'a'+"fun"-0x60 ===> 0x61 + "fun" - 0x61 ===> "fun" + 1
文字列アドレスに1を加えるということは、2文字目のアドレスを示すとい
うことになります。
"fun" + 1 ===> "un"
したがって最初のソースコードは次のソースコードと同じ意味になります。
main(){ printf( "%six\n", "un" );}
== Step 6: =========================================================
ここで printf関数 の第1引数の中の "%s" は第2引数の文字列で置き換え
て出力されますので、最終的には次の文字列が表示されることになるわけで
す。
"unix"(+改行)
以上、お分かりいただけたでしょうか?
まだ分からない点などありましたら、コメントに書き込んで下さい。
Jizou
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# 10個の実数に対する降順ソート結果を出力するプログラムを作りたいのですが、以下のプログラムをどう直せ 1 2022/07/09 22:16
- iOS Unix実行ファイルの開き方 1 2022/06/07 12:47
- UNIX・Linux UNIXのマニュアルを日本語訳するだけで人生が変わるようになってくれませんか。 ていうかそれが仕事に 2 2023/08/24 12:56
- C言語・C++・C# 3×3のラテン方陣をつくるプログラムを作成したのですが、(↓) #include <stdio.h> 5 2023/07/10 01:53
- C言語・C++・C# C言語 3 2022/10/04 15:07
- JavaScript ブックマークレットについて 2 2022/10/09 11:48
- C言語・C++・C# c言語 5 2023/04/27 13:20
- C言語・C++・C# LU分解法のピボッティングについて(C言語/gcc-9) 3 2022/07/11 23:10
- C言語・C++・C# C言語プログラム変更 2 2022/12/21 15:03
- C言語・C++・C# LU分解法のピボット選択機能実装について(C言語・gcc-9) 1 2022/07/22 15:20
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
[C言語]fputsとfprintfの違い
-
エクセルでアルファベットか数...
-
C言語で文字列の中の文字列のカ...
-
Excelはなんで先頭の0を消すん...
-
マクロ処理でのループの記述に...
-
【Excel VBA】複数ある特定の文...
-
sedなどで、特定の文字列の後の...
-
文字列からカンマを取り除きたい
-
エクセルでセル内の文字列の最...
-
Left関数とRight関数を合わせた...
-
A B C D E の五文字のすべてを...
-
VBAにおける文字列結合と繰り返...
-
VBの「As String * 128」とは?
-
OnTime 使用時のプロシージャへ...
-
EXCELで=より左の文字を一括で...
-
エクセルで文字列をtxtファイル...
-
【COBOL】文字列から数値項目に...
-
同一セル内に関数と文字列を同...
-
StringGridで選択した箇所の文...
-
MS SQLServer のSQLで文字列の...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
エクセルでアルファベットか数...
-
EXCELで=より左の文字を一括で...
-
文字列からタブコードを取り除...
-
Excelで3E8を3.00E+8にしない方...
-
VBAでの Replace関数で、ワイル...
-
Excelで指数表現しないようにす...
-
[C言語]fputsとfprintfの違い
-
エクセルで文字列をtxtファイル...
-
同一セル内に関数と文字列を同...
-
エクセルで文字列の最大値を抽...
-
Excelはなんで先頭の0を消すん...
-
MS SQLServer のSQLで文字列の...
-
エクセル 数値データを桁をそ...
-
Left関数とRight関数を合わせた...
-
VBA2005 16進を2桁で表示したい。
-
VBの「As String * 128」とは?
-
Msgboxの×が押されたとき
-
sedなどで、特定の文字列の後の...
-
【Excel VBA】複数ある特定の文...
-
OnTime 使用時のプロシージャへ...
おすすめ情報