Why char s1[] and char *s2 Aren’t the Same: Deep Dive into C Arrays vs Pointers
This article explains the fundamental differences between C arrays and pointers by examining memory layout, mutability, sizeof behavior, function parameter handling, multidimensional arrays, and practical best‑practice guidelines, providing clear code examples that reveal why declarations like char s1[] = "liangxu" and char *s2 = "liangxu" behave differently.
1. Memory layout
When declaring char s1[] = "liangxu";, the compiler allocates a contiguous block on the stack large enough for the characters plus the terminating null. The array name s1 is the address of the first element and cannot be assigned.
#include <stdio.h>
int main(void) {
char s1[] = "liangxu";
printf("s1 address: %p
", (void*)s1);
printf("s1 size: %zu bytes
", sizeof(s1));
for (int i = 0; i < sizeof(s1); i++) {
printf("s1[%d] = '%c', address: %p
", i, s1[i], (void*)&s1[i]);
}
return 0;
}Running the program shows that each character occupies consecutive addresses. Assigning s1 = "hello"; is a compile‑time error because the array name is not a modifiable lvalue.
1.1 Pointer memory layout
For char *s2 = "liangxu"; the string literal resides in the read‑only data segment. The compiler allocates a pointer variable on the stack (4 bytes on 32‑bit, 8 bytes on 64‑bit) that holds the address of that literal.
#include <stdio.h>
int main(void) {
char *s2 = "liangxu";
printf("s2 pointer address: %p
", (void*)&s2);
printf("s2 size: %zu bytes
", sizeof(s2));
printf("string address: %p
", (void*)s2);
for (int i = 0; s2[i] != '\0'; i++) {
printf("s2[%d] = '%c', address: %p
", i, s2[i], (void*)&s2[i]);
}
return 0;
}The pointer’s address differs from the literal’s address; the literal is stored in a non‑writable segment.
2. Mutability
Because s1 resides in writable stack memory, its contents can be changed:
#include <stdio.h>
#include <string.h>
int main(void) {
char s1[] = "liangxu";
printf("Before: %s
", s1);
s1[0] = 'L';
strcpy(s1, "LIANGXU");
printf("After: %s
", s1);
return 0;
}Modifying the literal through s2 causes a segmentation fault:
#include <stdio.h>
int main(void) {
char *s2 = "liangxu";
printf("Before: %s
", s2);
// s2[0] = 'L'; // crashes (read‑only memory)
s2 = "hello"; // legal: reassign the pointer
printf("After reassign: %s
", s2);
return 0;
}3. sizeof operator
For an array, sizeof(s1) yields the total number of bytes occupied by the array (including the terminating '\0'). For a pointer, sizeof(s2) yields the size of the pointer itself.
#include <stdio.h>
#include <string.h>
int main(void) {
char s1[] = "liangxu";
char *s2 = "liangxu";
printf("sizeof(s1) = %zu
", sizeof(s1)); // 8
printf("sizeof(s2) = %zu
", sizeof(s2)); // 4 or 8
printf("strlen(s1) = %zu
", strlen(s1)); // 7
printf("strlen(s2) = %zu
", strlen(s2)); // 7
return 0;
}When an array is passed to a function it decays to a pointer, so sizeof inside the function reports the pointer size. Pass the length explicitly:
void print_size(char str[]) {
// sizeof(str) is actually sizeof(char*)
printf("Inside sizeof(str) = %zu
", sizeof(str));
}
void print_size_correct(char str[], size_t len) {
printf("Array length: %zu
", len);
for (size_t i = 0; i < len; i++) {
printf("%c ", str[i]);
}
printf("
");
}4. Arrays vs pointers in function parameters
Although the syntax may suggest an array, the parameter is treated as a pointer. Modifying the pointed‑to characters works, but reassigning the parameter does not affect the caller’s variable.
void modify_string1(char str[]) { strcpy(str, "hello"); }
void modify_string2(char *str) { strcpy(str, "world"); }
void modify_pointer(char *str) { str = "new string"; } // local only
void modify_pointer_correct(char **str) { *str = "new string"; }5. Multidimensional arrays vs array of pointers
A true multidimensional array is a single contiguous block; an array of pointers stores separate addresses.
#include <stdio.h>
int main(void) {
char arr1[][8] = {"liangxu", "hello", "world"};
char *arr2[] = {"liangxu", "hello", "world"};
printf("arr1 size: %zu
", sizeof(arr1)); // 3*8 = 24
printf("arr2 size: %zu
", sizeof(arr2)); // 3 * pointer size
arr1[0][0] = 'L';
printf("arr1[0] after modify: %s
", arr1[0]);
arr2[0] = "LIANGXU"; // change pointer, not the literal
printf("arr2[0] after reassign: %s
", arr2[0]);
return 0;
}6. Practical guidelines
6.1 Use an array when a mutable buffer with fixed size is required
void process_sensor_data(void) {
char buffer[64];
sprintf(buffer, "Temp: %d, Humidity: %d", read_temp(), read_humidity());
uart_send_string(buffer);
}6.2 Use a pointer for read‑only string literals or to avoid copying large data
const char* get_error_message(int error_code) {
switch (error_code) {
case 0: return "Success";
case 1: return "Invalid parameter";
case 2: return "Timeout";
default: return "Unknown error";
}
}7. Conclusion
Arrays allocate writable contiguous memory on the stack, while pointers refer to literals stored in read‑only segments. sizeof behaves differently, and arrays decay to pointers when passed to functions. Choose arrays for mutable, fixed‑size data and pointers for read‑only or flexible references to avoid bugs and memory errors in embedded C.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Liangxu Linux
Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
