まあ >>750 のコードは、exit() がスキップされるのを期待したんだろう。

s4[400] は、exit() の呼び出し元のアドレスを格納したスタックの直前の領域に確保される。
ANSI では int a4[400]; を宣言した時に a4[400] にアクセスできる事を保証しているので、
実際には sizeof(int) * 401 バイトの領域が確保される。
つまり、a4[401] は呼び出し元のアドレスが格納されているので、これを書き換えてやると関数から
戻る先が換えられる。

なお、int s4[N]; の時に s4[N + 1] にアクセスすればいいので、N == 400 である必要は特に無い。
あと、引数は呼び出し元のアドレスより後のスタックに格納されるので、いくつあるかは関係無い。


が、これがうまくいくのは余程限定された状況でだな。
「i386 上」 だけでは成り立たない。

コンパイラが、変数を必ずスタックに、詰めて確保する事。
sizeof(int) == sizeof(void (*)()) が成り立つ事。
操作した戻り先のアドレスに、必ず安全なコードが書かれる事。
コードが最適化されない事。
デバッグモードでコンパイルされない事。

これだけの条件が揃う事はあまりない。
よって >>750 はクソ。