edge of cuboid

edge of cuboid 終了。C は、Rolling division に続き、vprintf() だった。以下、トップ nai さんの解。inaniwa さんも同じだ。

main(a,b,c){for(;~scanf("%d %d %d\n",&a,&b,&c);vprintf())a/=b/=c=sqrt(c*b/a);}

これは凄いな。基本は前の日記(Rolling division)で書いたことと同じだが、今回は、もう少し複雑だ。引数が省略された vprintf() は、scanf() への引数と同じものが渡るが、あくまで、vprintf() が使うのは、

"%d %d %d\n", &a

の部分のみである。&b や &c はとりあえず使われない。では、b や c の値はどうやって、vprintf() に渡るかというと、それは、main() の引数に、

main(a,b,c)

と並んでいるので、a, b, c が vprintf() が期待している引数構造になっているからだ。main() の引数の構造は以下の通り。

main(a,b,c){printf("%08x : %08x : %08x\n",&a,&b,&c);}
// ==> bfb01b60 : bfb01b64 : bfb01b68

つまり、引数があるスタックの構造は、引数の順番に、その引数の値がはいる int が並んだ、int の配列構造だ。つまり、前回の日記で説明したとおり、b、c は、a の次に vprintf() が期待する構造通りに並んでいるということだ。
なので、例えば、元の nai さんの解答に対し、

b;c;main(a){for(;~scanf("%d %d %d\n",&a,&b,&c);vprintf())a/=b/=c=sqrt(c*b/a);}

のように、main() の引数構造を壊すと、もちろん正しい答えは得られない。
逆に、

a[3];main(){for(;~scanf("%d %d %d\n",a,a+1,a+2);vprintf())a[0]/=a[1]/=a[2]=sqrt(a[2]*a[1]/a[0]);}

のように、main() の引数と同じ配列構造を使えば、うまくいく。
なお、

a,b,c;main(){for(;~scanf("%d %d %d\n",&a,&b,&c);vprintf())a/=b/=c=sqrt(c*b/a);}

は、a,b,c の並び順がこの通りにならないのでうまくいかない(コンパイラは、b,c,a の順に配置するようである)。なので、

a,b,c;main(){for(;~scanf("%d %d %d\n",&b,&c,&a);vprintf())b/=c/=a=sqrt(a*c/b);}

とするとうまくいく。

main() の引数 + scanf() + vprintf() の組み合わせは、今後も活躍しそうだな。