Assume the following declarations:
char arr[6] = "hello";
char *ap = "hello";
Here's one possible memory map showing the outcome of those declarations (all addresses are made up out of thin air and don't represent any real-world architecture):
Item Address 0x00 0x01 0x02 0x03
---- ------- ---- ---- ---- ----
"hello" 0x00008000 'h' 'e' 'l' 'l'
"hai" 0x00008004 'o' 0x00 'h' 'a'
0x00008008 'i' 0x00 0x?? 0x??
...
arr 0x82340000 'h' 'e' 'l' 'l'
0x82340004 'o' 0x00 0x?? 0x??
ap 0x82340008 0x00 0x00 0x80 0x00
The string literal "hello"
is stored as a 6-element array of char
with static storage duration at address 0x0008000
. The string literal "hai"
is stored as a 4-element array of char
with static storage duration at address 0x00080006
. The contents of a string literal may be stored in a read-only section of memory (depends on the platform). The behavior on attempting to modify the contents of a string literal is undefined; the code is considered erroneous, but the compiler isn't required to handle the situation in any particular way. You may get a segfault, or the change simply won't be applied, or the change will be applied as you expect. I'm assuming that multiple instances of a string literal in the source code will map to a single instance in memory (which is the usual case IME).
Except when it is the operand of the sizeof
or unary &
operators, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T
" will be converted ("decay") to an expression of type "pointer to T
", and the value of the expression will be the address of the first element of the array. The resulting pointer is a non-modifiable lvalue.
The declaration
char arr[6] = "hello";
declares arr
as a 6-element array of char
with auto extent, and the contents of the string literal "hello"
are copied into it. You can modify the values of arr[0]
through arr[5]
all you want, so you can write
a[0] = 'a';
but you cannot write something like
arr = "hai";
because while both of the expressions arr
and "hai"
are converted to pointer values as described above, arr
isn't a pointer variable; there's no storage associated with arr
apart from the array elements themselves, so there's no place to assign the result of "hai"
(0x00008006
).
The declaration
char *ap = "hello";
declares ap
as a pointer to char, and assigns the result of the expression "hello"
to it. In this case, the string literal is not the operand of the sizeof
or unary &
operators, and it isn't being used to initialize the contents of an array, so it is converted to a pointer expression, and its value is the address of the first element of the array, or 0x0008000
.
This is almost the mirror opposite of arr
; you cannot update the contents of ap[0]
through ap[5]
, but you can assign a new pointer value to ap
, so
ap = "hai";
works. After doing so, your memory map would look like
Item Address 0x00 0x01 0x02 0x03
---- ------- ---- ---- ---- ----
"hello" 0x00008000 'h' 'e' 'l' 'l'
"hai" 0x00008004 'o' 0x00 'h' 'a'
0x00008008 'i' 0x00 0x?? 0x??
...
arr 0x82340000 'a' 'e' 'l' 'l'
0x82340004 'o' 0x00 0x?? 0x??
ap 0x82340008 0x00 0x00 0x80 0x06