Remember that a string in C needs space for a null terminator. If there is no space, printing will continue "to the next nul". Here is how your memory looks at initialization:
h e l p \0 \0 \0 \0 d u d e \0
^ ^ ^
a b c
When you read in a string ab
in the location pointed to by b
:
h e l p \0 a b \0 d u d e \0
^ ^ ^
a b c
And all is well. But abc
gives:
h e l p \0 a b c \0 u d e \0
^ ^ ^
a b c
and when you print b
you will get abc
; printing c
will get you nothing (first character is '\0'
).
Finally, with an input of abcd
you get
h e l p \0 a b c d \0 d e \0
^ ^ ^
a b c
And printing c
will result in "d"
- exactly as you are seeing.
In fact, the order in which things are stored in memory is not "defined", although usually the compiler will do something similar to the above. So while you know that you can't write to memory that isn't yours, you can't be sure what will happen when you do (as in your case). That is why it is called "undefined behavior". You can't rely on other compilers giving you the same result - or even the same compiler giving you the same result...
Make sense?
The solution, of course, is to allocate more space to b
. That would result in more '\0'
between b
and c
, and nothing gets overwritten.
edit - I did just realize that it seems that the order in which b
and a
are stored is backwards from how I just described it - because it's a
, not c
that is getting overwritten. Which shows that the compiler orders things as it jolly well pleases, and that I ought to wear my glasses when I write detailed answers. But the principle is exactly the same - so I will "leave the rest as an exercise for the student".