In the first case, "string"
may be stored in a read-only area of the process, so attempting to modify the memory pointed to by p
would cause undefined behaviour.
In the second case, actual memory is allocated and initialised on the stack at runtime (or in an appropriate section of the process at program startup if it's not a local variable), so modifying the memory is OK.
The first case can be illustrated like this:
+---+ +---+---+---+---+---+---+---+
| | ----> | s | t | r | i | n | g | \0|
+---+ +---+---+---+---+---+---+---+
p
Whereas the second case is:
+---+---+---+---+---+---+---+
| s | t | r | i | n | g | \0|
+---+---+---+---+---+---+---+
p
The two declarations have a significant difference, although you may have heard that they are the same from low-quality C programming books.
The first is a pointer of type char *
, whereas the second is an array of type char []
. Array identifiers decay to a pointer in some contexts, but that doesn't make them pointers.
A pointer is merely an address and an array is "the whole thing" - in the first case sizeof(p)
yields the size of a pointer (usually 4
or 8
depending on the target machine), and in the second case it yields 7 * sizeof(char)
, the length of the actual string.