Question
In C, a string literal can be used in a declaration in two common ways:
char s[] = "hello";
or:
char *s = "hello";
What is the difference between these two declarations?
I want to understand what happens in terms of memory layout, mutability, and storage duration, both at compile time and at run time.
Short Answer
By the end of this page, you will understand why char s[] = "hello"; creates an array containing a copy of the string, while char *s = "hello"; creates a pointer to a string literal. You will also learn how their memory is stored, how they behave differently when modified, and why this distinction matters in real C programs.
Concept
In C, a string literal like "hello" is an array of characters stored by the implementation, with a terminating null character \0 added automatically.
These two declarations look similar, but they create very different objects:
char s[] = "hello";
char *s = "hello";
char s[] = "hello";
This declares s as an array of 6 characters:
{'h', 'e', 'l', 'l', 'o', '\0'}
The contents of the string literal are copied into the array when s is initialized. After that, s is its own array object.
shas storage for 6charvalues.- The array is modifiable if it is not declared
const. sizeof(s)gives the full array size, which is .
Mental Model
Think of these two forms like this:
char s[] = "hello";means make me my own writable notepad and copyhelloonto it.char *s = "hello";means give me the address of a printed sign that already sayshello.
With the notepad, you can erase and rewrite letters:
s[0] = 'H';
With the sign, you are only pointing at something that already exists somewhere else. Trying to rewrite the sign is not allowed safely.
Also:
- an array is the actual storage
- a pointer is only an address
That single idea explains most of the behavior difference.
Syntax and Examples
Core syntax
char s[] = "hello";
char *p = "hello";
Example 1: Array initialized from a string literal
#include <stdio.h>
int main(void) {
char s[] = "hello";
s[0] = 'H';
printf("%s\n", s);
return 0;
}
Output:
Hello
Explanation:
sis an array with its own storage.- The characters from
"hello"are copied into it. - Changing
s[0]is allowed.
Example 2: Pointer to a string literal
#include <stdio.h>
int {
*p = ;
(, p);
;
}
Step by Step Execution
Consider this code:
#include <stdio.h>
int main(void) {
char s[] = "hello";
char *p = "hello";
printf("%c %c\n", s[1], p[1]);
return 0;
}
Step-by-step
- The compiler sees the string literal
"hello". - That literal represents the character sequence:
'h', 'e', 'l', 'l', 'o', '\0'
-
For
char s[] = "hello";- space for 6 characters is created for
s - those 6 characters are copied into
s
Memory idea:
- space for 6 characters is created for
Real World Use Cases
When char s[] = "hello"; is useful
Editable local strings
char filename[] = "report.txt";
filename[0] = 'R';
Use this when you want to modify the characters.
Fixed-size local buffers initialized with text
char status[] = "pending";
This is common when a program starts with default text and later updates it.
When char *s = "hello"; is useful
Referring to constant message text
char *message = "File not found";
This is useful when you only need to read or print the text.
Selecting one of several literals
char *level;
if (error) {
level = "error";
} else {
level = "ok";
}
The pointer can be redirected to different string literals easily.
Returning or passing read-only text
Real Codebase Usage
In real projects, developers usually make the distinction more explicit.
Common pattern: use const char * for literals
const char *message = "hello";
This communicates:
- the text should not be modified
- the variable is just a pointer to existing character data
Common pattern: arrays for writable buffers
char buffer[64] = "hello";
This is used when code will:
- append text
- replace characters
- tokenize the string
- pass it to functions that modify the buffer
Validation and defensive coding
When a function should only read a string:
void print_name(const char *name) {
if (name == NULL) {
return;
}
printf("%s\n", name);
}
This is a common pattern in production C code:
const char *for read-only input
Common Mistakes
1. Trying to modify a string literal through a pointer
Broken code:
char *s = "hello";
s[0] = 'H';
Why this is wrong:
- the pointer refers to a string literal
- modifying it causes undefined behavior
Safer version:
char s[] = "hello";
s[0] = 'H';
Or if it should be read-only:
const char *s = "hello";
2. Assuming an array and a pointer are the same thing
Broken thinking:
- both work with
%s - both use
[] - therefore they are identical
They are not identical:
- an array stores elements directly
- a pointer stores an address
3. Using sizeof on a pointer to get string length
Broken code:
Comparisons
| Concept | char s[] = "hello"; | char *s = "hello"; |
|---|---|---|
What s is | Array of char | Pointer to char |
| Memory ownership | Own storage for characters | Stores address only |
| Initial data | Copy of literal placed in array | Points to literal |
| Modifiable characters | Yes | No, not safely |
Reassign s | No | Yes |
sizeof(s) | Size of entire array | Size of pointer |
Cheat Sheet
char s[] = "hello"; // array containing a copy: {'h','e','l','l','o','\0'}
char *p = "hello"; // pointer to string literal
const char *q = "hello"; // preferred for read-only literal
- String literals are null-terminated.
char s[] = "hello";creates writable array storage.char *p = "hello";creates a pointer to literal storage.- Modifying a string literal is undefined behavior.
- Arrays are not assignable.
- Pointers are assignable.
sizeof(array)gives total bytes in the array.sizeof(pointer)gives pointer size.strlen(string)gives character count before\0.
Quick rules:
- Want to edit the text? Use an array.
- Want to point at fixed text? Use
const char *. - Need a function to read a string? Usually use
const char *.
Example:
char name[] = ;
name[] = ;
*msg = ;
FAQ
Is char s[] = "hello"; the same as char *s = "hello";?
No. The first creates an array containing the characters. The second creates a pointer to a string literal.
Can I modify char *s = "hello";?
You should not. Modifying the string literal through that pointer causes undefined behavior.
Why does sizeof give different results?
Because in one case s is an array, and in the other case s is a pointer. Arrays and pointers are different types.
Where is the string literal stored?
The C standard does not require a specific memory section, but implementations typically place string literals in static storage, often in read-only memory.
Does char s[] = "hello"; copy the string?
Yes. The array is initialized with the literal's characters, including the terminating \0.
Why do many examples use const char * instead of char *?
Because string literals should be treated as read-only. const char * makes that intent clear and helps prevent mistakes.
Can two pointers to the same literal share storage?
Mini Project
Description
Build a small C program that demonstrates the practical difference between a writable character array and a pointer to a string literal. This helps you see memory behavior, modification rules, and reassignment in one place.
Goal
Create a program that safely modifies an array-based string, reassigns a pointer-based string, and prints the differences using sizeof and output.
Requirements
- Declare one string using
char name[] = "hello"; - Declare one string using
const char *message = "hello"; - Modify the first character of the array-based string
- Reassign the pointer-based string to a different literal
- Print both values and print their
sizeofresults
Keep learning
Related questions
Array-to-Pointer Conversion in C and C++ Explained
Learn what array-to-pointer conversion means in C and C++, how array decay works, and how it differs from a pointer to an array.
Building More Fault-Tolerant Embedded C++ Applications for Radiation-Prone ARM Systems
Learn practical C++ and compile-time techniques to reduce soft-error damage in embedded ARM systems exposed to radiation.
C Pointer to Array vs Array of Pointers: How to Read Complex Declarations
Learn the difference between pointer-to-array and array-of-pointers in C, plus a simple rule for reading complex declarations correctly.