String Literal Storage Duration and Mutability in C

In the C programming language, character string literals are fundamental constructs whose memory management and write permissions are strictly regulated by the ISO C standard. This article examines the exact standard definitions governing character string literals, focusing specifically on their static storage duration, their formal type designation, and the undefined behavior that occurs when a program attempts to modify them.

Storage Duration

According to the ISO C Standard (section 6.4.5 in C99, C11, and C17), string literals have static storage duration.

When the compiler encounters a string literal—such as "hello"—it creates an unnamed array of characters initialized with the given sequence and automatically appends a terminating null character ('\0'). Because the storage duration is static, this memory is reserved at program startup and persists for the entire lifetime of the program execution. It is not allocated on the stack (automatic storage duration) nor on the heap (allocated storage duration).

Additionally, the standard allows implementations to share identical string literals. If two distinct parts of a program reference "hello", the compiler and linker are permitted to store only a single instance in memory to conserve space.

Formal Type and Mutability

The type of a string literal in C is defined as an array of char (specifically, char[N], where N is the number of characters plus one for the null terminator). Unlike C++, where string literals have the type const char[N], C maintains the non-const char[] designation for historical compatibility with code written prior to the introduction of the const keyword.

Despite having a non-const type, string literals are immutable by standard mandate. Section 6.4.5, paragraph 7 of the ISO C standard explicitly states:

"If the program attempts to modify such an array, the behavior is undefined."

Because modifying a string literal is classified as undefined behavior, the standard does not require any specific runtime diagnostic or compilation failure. Modern operating systems and toolchains typically place string literals in read-only memory segments (such as the .rodata segment in ELF binaries). Consequently, attempting to write to a string literal usually triggers a hardware-level protection fault, resulting in a segmentation fault or access violation at runtime.

Pointer to Literal vs. Array Initialization

Understanding the mutability of string literals requires distinguishing between pointing directly to a literal and using a literal to initialize a character array:

  1. Pointer to a String Literal:

    char *str = "Hello, World!";
    str[0] = 'h'; /* Undefined Behavior */

    Here, str points directly to the statically allocated string literal in read-only storage. Attempting to modify str[0] invokes undefined behavior. To prevent accidental modification at compile time, pointers to literals should always be declared as const char *.

  2. Array Initialized by a String Literal:

    char arr[] = "Hello, World!";
    arr[0] = 'h'; /* Valid */

    In this case, arr is an independent array with its own storage duration (automatic if declared inside a function). The string literal serves merely as an initialization template; the characters are copied into the storage allocated for arr. Mutating arr modifies the copy, not the original string literal, and is entirely safe and defined.