>>1
変数 a は char へのポインタ のポインタです。
変数 s は char の配列、つまり文字列自体です。これは固定的に確保されているので、「s のアドレスは一定」です(これ重要)
a[i] は char へのポインタです。( a の1から3番目の要素は char へのポインタなので)

a[i] = new char[strlen(s) + 1]; で、s の長さに応じたメモリを確保し、
a[i] がそこを指すようにしています。
(>>1のコードではこのメモリを開放し忘れています。)
strcpy(a[i], s); で a[i] の指すアドレスへ s の指すアドレスから strcpy
しています。
これを a[i] = s; に置き換えるとすると、
s をポインタとしてみた時の値は一定なので、a[0] から a[2] までに全て
同じ値が入ります。
結果として どれを表示しても同じ文字列が表示されます。
( a[0] から a[2] が指しているのは全て s という配列の「中身」です。)

これが理解できないという事はポインタ、アドレス等について
( >1 のコードを見る限りメモリの確保と開放についても)
理解できていないという事だと思いますので、そこらへんを重点的に勉強しましょう。
コンピュータの動く仕組みを漠然とでもいいのでイメージできるようになると
大分理解できるようになると思いますので頑張りましょう。