Equivalence of Character Arrays and Pointers in C Function Parameters and Immutability of String Literals

Dec 04, 2025 · Programming · 10 views · 7.8

Keywords: C Programming | Function Parameters | String Literals | Pointer-Array Equivalence | Undefined Behavior

Abstract: This paper thoroughly examines the complete equivalence between char arr[] and char *arr declarations in C function parameters, analyzing the behavior when string literals are passed as arguments through code examples. It explains why modifying string literals leads to undefined behavior, compares stack-allocated arrays with pointers to read-only memory, and details the memory mechanism of parameter passing during function calls. Based on high-scoring Stack Overflow answers, this article systematically organizes core concepts to provide clear technical guidance for C programmers.

Equivalence in Function Parameter Declarations

In C function parameter lists, the declarations char arr[] and char *arr have identical semantics. When processing function prototypes and definitions, compilers automatically convert array-form parameters to pointer form. This equivalence applies not only to function definitions but also to function declarations.

// The following two function declarations are completely equivalent
void process_string(char str[]);
void process_string(char *str);

// The following two function definitions are also completely equivalent
void process_string(char str[]) {
    // Function body
}

void process_string(char *str) {
    // Function body
}

Memory Characteristics of String Literals

String literals such as "MyString" are typically stored in read-only memory regions during program execution. When a string literal is passed as a function argument, what is actually passed is a pointer to this read-only memory area. Attempting to modify the content of a string literal results in undefined behavior, which in most implementations manifests as a segmentation fault.

// Dangerous example: attempting to modify a string literal
void modify_string(char arr[]) {
    arr[0] = 'X';  // If arr points to a string literal, this causes undefined behavior
}

int main() {
    modify_string("MyString");  // Passing the address of a string literal
    return 0;
}

Memory Mechanism of Parameter Passing

During function calls, parameters are passed by value. For pointer-type parameters, what is passed is a copy of the pointer value (memory address), not the data pointed to by the pointer. This means the function receives a copy of the original pointer, but this copy still points to the same memory location.

// Parameter passing example
void demonstrate_parameter_passing(char *ptr) {
    // ptr is a copy of the pointer from the main function
    // but ptr and the original pointer point to the same memory address
    printf("Address value: %p\n", (void*)ptr);
}

int main() {
    char *str = "Literal";
    demonstrate_parameter_passing(str);
    return 0;
}

Comparison of Stack-Allocated Arrays and Pointers

Understanding the distinction between string literals and stack-allocated arrays is crucial. Stack-allocated character arrays have modifiable memory space within the function scope, while pointers to string literals reference read-only memory.

// Examples of correct and incorrect modifications
int main() {
    // Case 1: Pointer to string literal (not modifiable)
    char *ptr_to_literal = "Hello";
    // ptr_to_literal[0] = 'Z';  // Error: undefined behavior
    
    // Case 2: Stack-allocated character array (modifiable)
    char stack_array[] = "Hello";
    stack_array[0] = 'Z';  // Correct: modifying memory allocated on stack
    
    return 0;
}

Best Practice Recommendations

To avoid undefined behavior, it is recommended to treat string literals as static const char arrays. When a function needs to modify string content, it should receive stack- or heap-allocated character arrays, not string literals. For read-only string operations, use const char* parameters to clearly express intent.

// Safe function design examples
// Read-only version: using const qualifier
void print_string(const char *str) {
    printf("%s\n", str);
}

// Modifiable version: requiring callers to provide writable buffers
void modify_buffer(char buffer[], size_t size) {
    if (size > 0) {
        buffer[0] = 'X';
    }
}

int main() {
    // Safe call to read-only function
    print_string("Safe literal");
    
    // Safe call to modifiable function
    char writable[] = "Modifiable";
    modify_buffer(writable, sizeof(writable));
    
    return 0;
}

By understanding function parameter declaration equivalence, the read-only nature of string literals, and parameter passing mechanisms, C programmers can avoid common string handling errors and write safer, more reliable code.

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.