Search code examples
cpointersconstantsdeclarationstring-literals

Replacing (not modifying) 'const' values, legal?


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.


Solution

  • 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';