There are three types of standards behaviour you should be interested in.
1/ Defined behaviour. This will work on all complying implementations. Use this freely.
2/ Implementation-defined behaviour. As stated, it depends on the implementation but at least it's still defined. Implementations are required to document what they do in these cases. Use this if you don't care about portability.
3/ Undefined behaviour. Anything can happen. And we mean anything, up to and including your entire computer collapsing into a naked singularity and swallowing itself, you and a large proportion of your workmates. Never use this. Ever! Seriously! Don't make me come over there.
Copying more that 4 characters and a zero-byte to a char[5]
is undefined behaviour.
Seriously, it doesn't matter why your program crashes with 14 characters but not 13, you're almost certainly overwriting some non-crashing information on the stack and your program will most likely produce incorrect results anyway. In fact, the crash is better since at least it stops you relying on the possibly bad effects.
Increase the size of the array to something more suitable (char[14]
in this case with the available information) or use some other data structure that can cope.
Update:
Since you seem so concerned with finding out why an extra 7 characters doesn't cause problems but 8 characters does, let's envisage the possible stack layout on entering main()
. I say "possible" since the actual layout depends on the calling convention that your compiler uses. Since the C start-up code calls main()
with argc
and argv
, the stack at the start of main()
, after allocating space for a char[5]
, could look like this:
+------------------------------------+
| C start-up code return address (4) |
+------------------------------------+
| argc (4) |
+------------------------------------+
| argv (4) |
+------------------------------------+
| x = char[5] (5) |
+------------------------------------+
When you write the bytes Hello1234567\0
with:
strcpy (x, "Hello1234567");
to x
, it overwrites the argc
and argv
but, on return from main()
, that's okay. Specifically Hello
populates x
, 1234
populates argv
and 567\0
populates argc
. Provided you don't actually try to use argc
and/or argv
after that, you'll be okay.
However, if you write Hello12345678\0
(note the extra "8") to x
, it overwrites the argc
and argv
and also one byte of the return address so that, when main()
attempts to return to the C start-up code, it goes off into fairy land instead.
Again, this depends entirely on the calling convention of your compiler. It's possible a different compiler would always pad out arrays to a multiple of 4 bytes and the code wouldn't fail there until you wrote another three characters. Even the same compiler may allocate variables on the stack frame differently to ensure alignment is satisfied.
That's what they mean by undefined: you don't know what's going to happen.