Nth prime
inaniwa さんの解。ご自身のブログでも書かれているが、
P[9999];Q;*p;main(n){for(;Q?gets(P)&&...
この、配列 P の要素が 9999 を超えたときに、Q が non zero になることを利用した条件分岐、見事です。ただ、ちょっと気になったので、調べてみたら(っといっても、現象を見ただけで、理由までは分からないが…)、配列とその後の変数の名前によって、メモリー上の配置がかわってくるようだ。
P[1];Q;main(){printf("%08x %08x\n",P,&Q);} //-> 08049618 0804961c a[1];o;main(){printf("%08x %08x\n",a,&o);} //-> 08049618 0804961c a[1];p;main(){printf("%08x %08x\n",a,&p);} //-> 0804961c 08049618 a[1];q;main(){printf("%08x %08x\n",a,&q);} //-> 08049618 0804961c a[1];r;main(){printf("%08x %08x\n",a,&r);} //-> 08049618 0804961c a[1];s;main(){printf("%08x %08x\n",a,&s);} //-> 0804961c 08049618 a[1];t;main(){printf("%08x %08x\n",a,&t);} //-> 0804961c 08049618 a[1];u;main(){printf("%08x %08x\n",a,&u);} //-> 08049618 0804961c a[1];v;main(){printf("%08x %08x\n",a,&v);} //-> 08049618 0804961c a[1];w;main(){printf("%08x %08x\n",a,&w);} //-> 0804961c 08049618 a[1];x;main(){printf("%08x %08x\n",a,&x);} //-> 0804961c 08049618 a[1];y;main(){printf("%08x %08x\n",a,&y);} //-> 08049618 0804961c a[1];z;main(){printf("%08x %08x\n",a,&z);} //-> 08049618 0804961c
配列 a に対して、変数名が p/s/t/w/x の時、メモリー上の配置が逆順になる。ランダムというわけではなく、コンスタントにそうなる。また、
p;q;main(){printf("%08x %08x\n",&p,&q);} //-> 08049618 0804961c q;p;main(){printf("%08x %08x\n",&p,&q);} //-> 08049618 0804961c
となり、変数定義の出現順ではなく、名前によりメモリー上の配置順が決まるようだ。これらの例だけでは規則性は見出せないが、コンパイラーの癖ということなのだろう。
このあたり、変数とバッファーの確保方法で、割とゴルフに影響がありそう。つまり、例えば、
q;p;main(){...;gets(&p);...}
は、q の内容を破壊するため、たいてい SEGV になるが、
p;q;main(){...;gets(&q);...}
は、p の内容を破壊しないので、&q から効率よくバッファーを確保できる。以下のように宣言する必要がないわけだ。
p;q[9];main(){...;gets(q);...}
#ゴルフ以外には、まったく役に立たない知識。