string literals in C are constants, not variables. That's why one should use a double pointer to use the same pointer with a different string literal.
Sorry, but this is false and wrong.
First:§ 6.4.5 String literals
§ 6.4.5(6) In translation phase 7, a byte or code of value zero is appended to each multibyte character sequence that results from a string literal or literals. (*79) The multibyte character sequence is then used to initialize an array of static storage duration and length just sufficient to contain the sequence. For
character string literals, the array elements have type char, and are initialized with the individual bytes of the multibyte character sequence. ... [different types] ... The value of a string literal containing a multibyte character or escape sequence not represented in the execution character set is implementation-defined.
(7) It is unspecified whether these arrays are distinct provided their elements have the appropriate values. If the program attempts to modify such an array, the behavior is undefined.
(*79) A string literal need not be a string (see 7.1.1), because a null character may be embedded in it by a \0 escape sequence.
Next: quoted strings in C come in a few flavors. One flavor is a string literal used to initialize a declared array. When so used, the quoted string is translated into an array initializer and "disappears". Another flavor is a quoted literal used to initialize a pointer. This becomes an "anonymous array" someplace in memory, and is pointed to by the pointer. Note the following:§ 6.7.9(14) An array of character type may be initialized by a character string literal or UTF–8 string literal, optionally enclosed in braces. Successive bytes of the string literal (including the terminating null character if there is room or if the array is of unknown size) initialize the elements of the array.
And later:§ 6.7.9(32) EXAMPLE 8 The declaration
Code:
char s[] = "abc", t[3] = "abc";
defines “plain” char array objects s
and t
whose elements are initialized with character string literals. This declaration is identical to
Code:
char s[] = { ’a’, ’b’, ’c’, ’\0’ },
t[] = { ’a’, ’b’, ’c’ };
The contents of the arrays are modifiable. On the other hand, the declaration
defines p
with type “pointer to char” and initializes it to point to an object with type “array of char” with length 4 whose elements are initialized with a character string literal. If an attempt is made to use p
to modify the contents of the array, the behavior is undefined.
In my experience, most desktop compilers put the quoted strings into memory somewhere, and you're able to modify them with no ill effect. This is a legacy of pre-ANSI C, where literal strings were sometimes used as cheap buffers. The rogue-like game "Larn" used this to hide/reveal information like details of inventory items and names of spells. Also, at least one system utility on Sun OS used literals with blank spaces as a buffer, and just called sprintf to write values into the strings before displaying them. (Again, all pre-ANSI. But I'll bet cash money they still work!)
For reasons that baffle me, GCC has a warning for writing to string literals but it is not included in -Wall. Because of course -Wall is really -Wmany...
So string literals in C are not const. But modifying them is "undefined behavior." So undefined that it just works most of the time.
Let's move on to your second sentence. ;-)
The reason to use a double pointer to change the string literals that you are referencing is simply because you are passing a pointer to something you wish to modify. If you chose to return a replacement value and assign it in the caller, the extra layer of pointer would not be necessary:
Code:
void
change_my_pointer(
char ** p,
int rv)
{
char * result;
if (rv & 1) {
result = "BEFORE";
} else {
result = "AFTER";
}
*p = result;
}
char *
new_value_for_pointer(
int rv)
{
char * result;
if (rv & 1) {
result = "BEFORE";
} else {
result = "AFTER";
}
return result;
}
void
caller(void)
{
char * p = "abc";
rv = random_value();
change_my_pointer(&p, rv);
// vs
p = new_value_for_pointer(rv);
}
strings may reside in completely different memory locations, even though pointer IDs, as well as their addresses and values are identical. Because there is a difference between the actual address of the pointer in memory and its content (also an address but of the object/data it points to):
I think you got this right. I'm not 100% sure what you're saying vis-a-vis "pointer IDs", but different string literals definitely reside in different memory locations. (Note that "identical" string literals may or may not reside in different memory locations, at the whim of the compiler. This is part of the problem with __FILE__ versus __func__ in C (& C++). With __FILE__ the committee declared that it would expand to a literal. (Which was good, because you could utilize it in the preprocessor as well as the compiler.) But some compilers were generating multiple copies of the literal in their compiled output, taking up too much space. With __func__ (added later) they declared that it expands to a "predefined identifier", and so it is only available at run-time.)