Here's a hypothetical memory map, showing the results of the two declarations:
0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07
0x00008000: 'n' 'o' 'w' ' ' 'i' 's' ' ' 't'
0x00008008: 'h' 'e' ' ' 't' 'i' 'm' 'e' '\0'
...
amessage:
0x00500000: 'n' 'o' 'w' ' ' 'i' 's' ' ' 't'
0x00500008: 'h' 'e' ' ' 't' 'i' 'm' 'e' '\0'
pmessage:
0x00500010: 0x00 0x00 0x80 0x00
The string literal "now is the time" is stored as a 16-element array of char at memory address 0x00008000. This memory may not be writable; it's best to assume that it's not. You should never attempt to modify the contents of a string literal.
The declaration
char amessage[] = "now is the time";
allocates a 16-element array of char at memory address 0x00500000 and copies the contents of the string literal to it. This memory is writable; you can change the contents of amessage to your heart's content:
strcpy(amessage, "the time is now");
The declaration
char *pmessage = "now is the time";
allocates a single pointer to char at memory address 0x00500010 and copies the address of the string literal to it.
Since pmessage points to the string literal, it should not be used as an argument to functions that need to modify the string contents:
strcpy(amessage, pmessage); /* OKAY */
strcpy(pmessage, amessage); /* NOT OKAY */
strtok(amessage, " "); /* OKAY */
strtok(pmessage, " "); /* NOT OKAY */
scanf("%15s", amessage); /* OKAY */
scanf("%15s", pmessage); /* NOT OKAY */
and so on. If you changed pmessage to point to amessage:
pmessage = amessage;
then it can be used everywhere amessage can be used.
True, but it's a subtle difference. Essentially, the former:
char amessage[] = "now is the time";
Defines an array whose members live in the current scope's stack space, whereas:
char *pmessage = "now is the time";
Defines a pointer that lives in the current scope's stack space, but that references memory elsewhere (in this one, "now is the time" is stored elsewhere in memory, commonly a string table).
Also, note that because the data belonging to the second definition (the explicit pointer) is not stored in the current scope's stack space, it is unspecified exactly where it will be stored and should not be modified.
Edit: As pointed out by Mark, GMan, and Pavel, there is also a difference when the address-of operator is used on either of these variables. For instance, &pmessage returns a pointer of type char**, or a pointer to a pointer to chars, whereas &amessage returns a pointer of type char(*)[16], or a pointer to an array of 16 chars (which, like a char**, needs to be dereferenced twice as litb points out).
An array contains the elements. A pointer points to them.
The first is a short form of saying
char amessage[16];
amessage[0] = 'n';
amessage[1] = 'o';
...
amessage[15] = '\0';
That is, it is an array that contains all the characters. The special initialization initializes it for you, and determines it size automatically. The array elements are modifiable - you may overwrite characters in it.
The second form is a pointer, that just points to the characters. It stores the characters not directly. Since the array is a string literal, you cannot take the pointer and write to where it points
char *pmessage = "now is the time";
*pmessage = 'p'; /* undefined behavior! */
This code would probably crash on your box. But it may do anything it likes, because its behavior is undefined.
I can't add usefully to the other answers, but I will remark that in Deep C Secrets, Peter van der Linden covers this example in detail. If you are asking these kinds of questions I think you will love this book.
P.S. You can assign a new value to pmessage
. You can't assign a new value to amessage
; it is immutable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With