Difference Between char s[] and char *s in C: Storage Mechanisms and Memory Management

Nov 20, 2025 · Programming · 12 views · 7.8

Keywords: C Programming | String Declaration | Memory Management | Character Array | Character Pointer | Storage Mechanism

Abstract: This article provides an in-depth analysis of the fundamental differences between char s[] = "hello" and char *s = "hello" string declarations in C programming. By comparing key characteristics including storage location, memory allocation mechanisms, modifiability, and scope, it explains behavioral differences at both compile-time and runtime with detailed code examples. The paper demonstrates that array declaration allocates modifiable memory on the stack, while pointer declaration references string literals in read-only memory regions, where any modification attempts lead to undefined behavior. It also explores equivalence in function parameters and practical programming considerations, offering comprehensive guidance for C string handling.

Storage Location and Memory Allocation Mechanisms

In C programming, char s[] = "hello" and char *s = "hello" may appear similar superficially, but they differ fundamentally in their underlying memory management mechanisms. The former declares a character array, while the latter declares a pointer to characters.

When using char s[] = "hello", the compiler allocates contiguous memory space on the stack sufficient to hold the string "hello" along with its null terminator \0. The string literal "hello" is initially stored in read-only memory, then copied to the newly allocated stack memory during runtime. This makes the array s a modifiable local variable, where operations like s[0] = 'J' are completely legal, changing the first character to 'J'.

In contrast, char *s = "hello" only declares a pointer variable s stored on the stack, but the string literal "hello" it points to resides in read-only memory (typically the code segment). This design means any attempt to modify the string content through this pointer (such as s[0] = 'J') results in undefined behavior, often manifesting as program crashes.

Compile-Time and Runtime Behavior Analysis

From a compilation perspective, the implementation of char *s = "hello" can be approximately understood as:

static const char __secret_anonymous_array[] = "hello";
char *s = (char *) __secret_anonymous_array;

The compiler secretly creates a static anonymous array to store the string literal, then sets pointer s to point to this array. Since this array has static storage duration and resides in read-only memory, modifying its content violates language specifications.

For char s[] = "hello", the compiler determines the array size (including \0) at compile time and dynamically allocates corresponding space on the stack during function invocation. At runtime, the string is copied from the read-only area to this writable memory region.

Memory Layout and Operational Characteristics Comparison

The two declaration methods exhibit significant differences in memory layout:

In terms of operational characteristics:

char s[] = "hello";
printf("%lu", sizeof(s)); // Outputs 6 (on 32-bit systems)
s[0] = 'J'; // Legal operation
// s = "world"; // Error: array name cannot be reassigned
char *s = "hello";
printf("%lu", sizeof(s)); // Outputs 4 (pointer size on 32-bit systems)
// s[0] = 'J'; // Undefined behavior, typically causes segmentation fault
s = "world"; // Legal: pointer can be reassigned to other strings

Special Case in Function Parameters

In function parameter declarations, char *x and char x[] are completely equivalent:

void foo(char *x);
void foo(char x[]); // Identical in all respects

This equivalence stems from C's parameter passing mechanism—arrays decay to pointers when passed as function parameters. However, in other contexts, the differences between them remain as described previously.

Scope and Lifetime Considerations

When char s[] = "hello" is declared within a function, the array is only valid within its containing scope. If the string needs to be returned, functions like strdup() should be used to create a copy, avoiding returning pointers to local variables.

If array declaration is used in global scope, the array has static storage duration with no lifetime issues. For char *s = "hello", the string literal itself has static storage duration, but the pointer variable remains subject to scope limitations.

Modern Compiler Warnings and Best Practices

Modern C compilers typically issue warnings for char *s = "hello": "deprecated conversion from string constant to 'char*'". This occurs because the pointer is not declared as const yet points to read-only memory.

It is recommended to use const char *s = "hello" to explicitly convey intent and prevent accidental modifications:

const char *s = "hello"; // Explicitly indicates pointing to constant string
// s[0] = 'J'; // Compile-time error, rather than runtime undefined behavior

This declaration approach enhances code safety while clearly communicating design intent, representing modern C programming best practices.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.