CPointers & Strings

Pointers & Strings

C has no built-in string type — a string is just a char array terminated by a \\0 byte, and strings are one of the places where pointers show up constantly in everyday code. This page focuses on one specific, classic gotcha: the difference between a pointer to a string literal and a real, modifiable array copy of one.

What a string literal actually is

When you write "hello" in your source code, the compiler stores those characters (plus a terminating \\0) somewhere in the program's memory, and the literal itself, when used as a value, gives you a char * pointing at the first character.

C
#include <stdio.h>

int main(void) {
    char *s = "hello";  // s points at the literal's first character

    printf("s      = %s\n", s);
    printf("s[0]   = %c\n", s[0]);
    printf("*(s+1) = %c\n", *(s + 1));

    return 0;
}
s      = hello
s[0]   = h
*(s+1) = e
char *s vs. char s[] — a critical difference

These two declarations look similar but behave very differently, and confusing them is one of the most common bugs new C programmers write:

C
char *s1 = "hello";   // s1 points to a string literal
char  s2[] = "hello";  // s2 is a genuine, modifiable array copy

s2 is a local array, initialized by copying the letters h, e, l, l, o, \\0 into its own storage on the stack. Modifying s2[0] is completely safe. s1, on the other hand, is just a pointer aimed at the literal "hello" itself, which many compilers place in read-only memory. Writing through s1 is undefined behavior.

Modifying a string literal crashes (or worse)
Attempting to modify a string literal through a `char *` pointer is undefined behavior. On many systems it triggers an immediate segmentation fault; on others it may silently corrupt memory. Never write through a pointer that was initialized directly from a string literal.

C
#include <stdio.h>

int main(void) {
    char *s1 = "hello";
    // s1[0] = 'H';   // UNDEFINED BEHAVIOR — often crashes: literal is read-only

    char s2[] = "hello";
    s2[0] = 'H';       // OK — s2 is a real, modifiable array
    printf("%s\n", s2);

    return 0;
}
Hello
Iterating a string with pointer arithmetic

Because a string is just a char array ending in \\0, an idiomatic (if slightly old-school) way to walk through it is to advance a pointer until it reaches the terminator, rather than indexing with [i]:

C
#include <stdio.h>

int main(void) {
    char s[] = "pointer";
    int count = 0;

    for (char *p = s; *p != '\0'; p++) {
        count++;
    }

    printf("length of \"%s\" is %d\n", s, count);
    return 0;
}
length of "pointer" is 7
This is essentially what strlen does
The standard library's own `strlen` function is implemented with exactly this kind of pointer-walking loop internally. Seeing the pattern here makes functions like `strlen`, `strcpy`, and `strcmp` far less mysterious once you get to the string library pages.
  • "hello" as a value is a char * pointing at storage the compiler set up for the literal — often read-only.

  • char *s = "hello"; points at that literal; writing through s is undefined behavior.

  • char s[] = "hello"; copies the characters into a fresh, modifiable local array — safe to write to.

  • Walking a string by advancing a char * pointer until it hits \0 is a classic, idiomatic C pattern.