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:
Pointer to a String Literal:
char *str = "Hello, World!"; str[0] = 'h'; /* Undefined Behavior */Here,
strpoints directly to the statically allocated string literal in read-only storage. Attempting to modifystr[0]invokes undefined behavior. To prevent accidental modification at compile time, pointers to literals should always be declared asconst char *.Array Initialized by a String Literal:
char arr[] = "Hello, World!"; arr[0] = 'h'; /* Valid */In this case,
arris 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 forarr. Mutatingarrmodifies the copy, not the original string literal, and is entirely safe and defined.