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);...}

#ゴルフ以外には、まったく役に立たない知識。