> But why it worked with two elements?
Pure dumb luck - nothing more.
Many malloc implementations pad the amount you ask for out to say a multiple of 8 bytes (or whatever the most restrictive alignment is on your machine). Small overruns can therefore go unnoticed for some time.
If you want better diagnosis, you need a tool like valgrind, or using another compiler.
Code:
$ valgrind ./a.out
1
==3120== Memcheck, a memory error detector
==3120== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==3120== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info
==3120== Command: ./a.out
==3120==
hello
BOZA!!!
==3120== Invalid write of size 4
==3120== at 0x804869B: push (foo.c:55)
==3120== by 0x80485E9: test (foo.c:34)
==3120== by 0x804853E: main (foo.c:18)
==3120== Address 0x419802c is 0 bytes after a block of size 4 alloc'd
==3120== at 0x4024F20: malloc (vg_replace_malloc.c:236)
==3120== by 0x804866C: push (foo.c:50)
==3120== by 0x80485E9: test (foo.c:34)
==3120== by 0x804853E: main (foo.c:18)
==3120==
==3120== Invalid write of size 4
==3120== at 0x80486A4: push (foo.c:56)
==3120== by 0x80485E9: test (foo.c:34)
==3120== by 0x804853E: main (foo.c:18)
==3120== Address 0x4198030 is 4 bytes after a block of size 4 alloc'd
==3120== at 0x4024F20: malloc (vg_replace_malloc.c:236)
==3120== by 0x804866C: push (foo.c:50)
==3120== by 0x80485E9: test (foo.c:34)
==3120== by 0x804853E: main (foo.c:18)
==3120==
==3120== Invalid write of size 4
==3120== at 0x80486AA: push (foo.c:57)
==3120== by 0x80485E9: test (foo.c:34)
==3120== by 0x804853E: main (foo.c:18)
==3120== Address 0x4198038 is 12 bytes after a block of size 4 alloc'd
==3120== at 0x4024F20: malloc (vg_replace_malloc.c:236)
==3120== by 0x804866C: push (foo.c:50)
==3120== by 0x80485E9: test (foo.c:34)
==3120== by 0x804853E: main (foo.c:18)
==3120==
==3120== Invalid read of size 4
==3120== at 0x80486B4: push (foo.c:57)
==3120== by 0x80485E9: test (foo.c:34)
==3120== by 0x804853E: main (foo.c:18)
==3120== Address 0x4198038 is 12 bytes after a block of size 4 alloc'd
==3120== at 0x4024F20: malloc (vg_replace_malloc.c:236)
==3120== by 0x804866C: push (foo.c:50)
==3120== by 0x80485E9: test (foo.c:34)
==3120== by 0x804853E: main (foo.c:18)
==3120==
==3120== Invalid write of size 4
==3120== at 0x80486BA: push (foo.c:57)
==3120== by 0x80485E9: test (foo.c:34)
==3120== by 0x804853E: main (foo.c:18)
==3120== Address 0x4198034 is 8 bytes after a block of size 4 alloc'd
==3120== at 0x4024F20: malloc (vg_replace_malloc.c:236)
==3120== by 0x804866C: push (foo.c:50)
==3120== by 0x80485E9: test (foo.c:34)
==3120== by 0x804853E: main (foo.c:18)
==3120==
==3120==
==3120== HEAP SUMMARY:
==3120== in use at exit: 4 bytes in 1 blocks
==3120== total heap usage: 1 allocs, 0 frees, 4 bytes allocated
==3120==
==3120== LEAK SUMMARY:
==3120== definitely lost: 4 bytes in 1 blocks
==3120== indirectly lost: 0 bytes in 0 blocks
==3120== possibly lost: 0 bytes in 0 blocks
==3120== still reachable: 0 bytes in 0 blocks
==3120== suppressed: 0 bytes in 0 blocks
==3120== Rerun with --leak-check=full to see details of leaked memory
==3120==
==3120== For counts of detected and suppressed errors, rerun with: -v
==3120== ERROR SUMMARY: 5 errors from 5 contexts (suppressed: 13 from 8)
Even with just one string, you see a lot of invalid write attempts, even though the end result is the program ending normally.