In your first case
is allocated on the stack in in the second case it is allocated on the heap.
When both strings are on the heap, you have a memory image like this:
dest: at some address
p: at dest + 20 + alignment (4 with 8 byte alignment) + heap info
If you now copy more than 20 characters including the NULL byte to
, this will overflow into
can't handle copying of overlapping memory but in this case it will work). Printing now
will show the full string while printing
will show only the end of the string. The heap at
is corrupted. But you will not recognize this when not using
The organization of stack memory is different from the heap memory: It uses memory in a reverse direction (starting at the initial size subtracting the size of the required memory). So the memory image looks like this (highest addresses first):
current stack top at some address
dest: top - 20
When now copying more than 20 bytes to
, this will overwrite the stack content on top. On the stack are other local variables, function parameters, and the return addresses of functions. In your case the return address of some function is most likely overwritten resulting in the access violation.
So the difference is between corrupted stack and heap memory where the stack corruption is much more dangerous because it effects program execution while heap memory mainly contains data (which may also lead to access violations when the memory contains pointers).