2

I know that const char * is a pointer to a const char, while char *const is a constant pointer to a char. I am testing this in the following code:

const char *s = "hello";    // Not permitted to modify the string "hello"
char *const t = "world";    // Not permitted to modify the pointer t

s = "hello2";   // Valid
// t = "world2";   // Invalid, gives compilation error

// *(s + 1) = 'a';    // Invalid, gives compilation error
*(t + 1) = 'a';       // Why does this not work?    

The last line does not give any error, but causes the program to terminate unexpectedly. Why is modifying the string pointed to by t not allowed?

Koderok
  • 1,903
  • 3
  • 15
  • 18
  • [c - Why do I get a segmentation fault when writing to a "char *s" initialized with a string literal, but not "char s\[\]"? - Stack Overflow](https://stackoverflow.com/questions/164194/why-do-i-get-a-segmentation-fault-when-writing-to-a-char-s-initialized-with-a) (C only, not C++, somehow this question has both tags) – user202729 Jun 18 '22 at 10:35

4 Answers4

7

t is pointing to a string literal it is undefined behavior to modify a string literal. The C++ draft standard section 2.14.5 String literals paragraph 12 says(emphasis mine):

Whether all string literals are distinct (that is, are stored in nonoverlapping objects) is implementation defined. The effect of attempting to modify a string literal is undefined.

The relevant section from the C99 draft standard is 6.4.5 String literals paragraph 6 which says(emphasis mine):

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.

On a typical modern Unix platform you will find string literals in the read-only segment which would result in a access violation if we attempt to modify it. We can use objdump to inspect the read-only section as follows:

objdump -s -j .rodata

we can see in the following live example that the string literal will indeed be found in the read-only section. Note that I had to add a printf otherwise the compiler would optimize out the string literal. Sample `objdump output:

Contents of section .rodata:
 400668 01000200 776f726c 64002573 0a00      ....world.%s..

An alternative approach would be to have t point to an array with a copy of a string literal like so:

char r[] = "world";    
char *const t = r ;
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • 1
    You state the standard, but you do not actually say why (how) the program terminates with an error... Just saying... Elchonon Edelson gives the actual reason, which I think is the correct answer. – Alexis Wilke Oct 15 '13 at 04:35
  • @AlexisWilke The standard is meant to be platform independent and such details are platform dependent which is why the standard uses such language as undefined behavior to encompass a whole range of behaviors which include working just fine but it can not be relied on. I added more details for a typical modern unix platform. – Shafik Yaghmour Oct 15 '13 at 04:48
3

Although string literals in C officially have a type of char[] (array of char, not const), the C standard specifically states that they must be treated as non-modifiable. Compilers tend to put string literals in a read-only segment, so attempting to modify them results in an access violation.

String literals are described in section 6.4.5 of the C11 standard (ISO/IEC 9899:2011).

This isn't my real name
  • 4,869
  • 3
  • 17
  • 30
1

You can bypass the compiler error by recast it as char*, as in *((char*)s + 1) = 'a'; but as it was already estated in other answers, this is undefined behaviour and will probably result in Segmentation Fault because you are editing a string literal.

Havenard
  • 27,022
  • 5
  • 36
  • 62
1

If you want to test it properly, initialize the strings in a function so the initialization can be dynamic and use strdup() for that.

int
main(int argc, char **argv)
{
    char *d1 = strdup("hello");
    char *d2 = strdup("world");

    const char *s = d1;
    char *const t = d2;

    ...

    free(d1);
    free(d2);
}

The d1 and d2 variables are mainly used so that the dynamic allocations can be properly freed using free() at the end. Also, as other answers suggest, always treat string literals as const char *.

Pavel Šimerda
  • 5,783
  • 1
  • 31
  • 31