A structured lesson workspace with readable content, hands-on examples, and a clean path to completion.
char s[] = "hello" and char *s = "hello" look similar. They are fundamentally different. The first creates a mutable array on the stack initialized with a copy of the string. The second creates a pointer to a string literal stored in read-only memory. Writing through the first is fine. Writing through the second is undefined behavior and will segfault on most platforms. This distinction is tested in interviews, causes real crashes, and confuses beginners every single year.
#include <stdio.h>int main(void) {char arr[] = "hello";char *ptr = "hello";printf("arr: %s (at %p)\n", arr, (void *)arr);printf("ptr: %s (at %p)\n", ptr, (void *)ptr);printf("sizeof(arr): %zu\n", sizeof(arr));printf("sizeof(ptr): %zu\n", sizeof(ptr));arr[0] = 'H';printf("Modified arr: %s\n", arr);return 0;}
sizeof(arr) is 6: five characters plus the null terminator. The array owns its storage. sizeof(ptr) is 8: the pointer itself on a 64-bit system. The pointer does not own the string. The addresses are in different memory regions: the array is on the stack (high address), the literal is in the read-only data segment (low address).
#include <stdio.h>int main(void) {char *ptr = "hello";printf("Before: %s\n", ptr);ptr[0] = 'H';printf("After: %s\n", ptr);return 0;}
The string literal lives in a read-only memory segment. The CPU's memory protection unit blocks the write. The OS delivers SIGSEGV. On some ancient systems or with certain compiler flags, the write might succeed and corrupt the literal, affecting every other pointer to the same string. That is worse than a crash. The crash is the safe outcome.
Use char arr[] when you need to modify the string. Use const char *ptr when the string is a constant and you only need to read it. The const qualifier on the pointer communicates intent and lets the compiler warn you if you accidentally try to write. If a function parameter is const char *, it promises not to modify the string. Passing a string literal to it is safe. Passing a mutable array is also safe because the function promised not to write.
This distinction is not a trivia question. It determines whether your program crashes, whether your data is mutable, and how much stack space you consume. Internalize it. Next: the null terminator, the single byte that defines what a C string is.
Finish the lesson once you have worked through the material. This awards ★ 30 XP.