Observe the following code:
const char *str1 = "foo";
printf("1.1: %s\n", str1);
str1 = "bar";
printf("1.2: %s\n\n", str1);
const char *str2[] = { "foo", "bar" };
printf("2.1: %s\n", str2[0]);
str2[0] = "baz";
printf("2.2: %s\n\n", str2[0]);
char *str3 = malloc(4);
strcpy(str3, "foo");
const char *str4[] = { str3, "bar" };
printf("3.1: %s -- %s\n", str4[0], str4[1]);
//str4[0][0] = 'z';
str4[0] = "bar";
str4[1] = "baz";
printf("3.2: %s -- %s\n", str4[0], str4[1]);
free(str3);
Wrapping it in a standard main
function and compiling with gcc -Wall -Wextra -o test test.c
, this gives no warnings and the output is:
1.1: foo
1.2: bar
2.1: foo
2.2: baz
3.1: foo -- bar
3.2: bar -- baz
When uncommenting the only commented line, gcc complains error: assignment of read-only location ‘*str4[0]’
. Of course this is expected, I only added that bit for completeness.
By my understanding all the other assignments are valid because I'm not modifying the already existing read-only memory, I'm replacing it in its entirety with another memory block (which is then also marked read-only). But is this legal throughout all C compilers, or is it still implementation-dependent and therefore can it result in undefined behaviour? It's a little hard to find good information on this because it always seems to be about modifying the existing memory through pointer magic or casting the const
away.
In this declaration
const char *str1 = "foo";
the pointer (variable) str1
is not constant. It is the string literal pointed to by the pointer str1
that is constant. That is the (non-constant) pointer str1
points to a constant object of the type const char
.
So you may not change the literal pointed to by the pointer like for example
str1[0] = 'g';
But you may change the variable str1
itself because it is not constant
str1 = "bar";
To declare the pointer str1
as a constant pointer you should write
const char * const str1 = "foo";
In this case you may not write
str1 = "bar";
Because now the pointer str1
itself is constant.
Pay attention to though in C string literals have types of non-constant character arrays nevertheless you may not change a string literal. Any attempt to change a string literal results in undefined behavior.
That is you may not write
char *str1 = "foo";
str1[0] = 'g';