C

Strings

C has no dedicated string type. What every other language calls a "string," C represents as a plain char array with one special rule: it ends with a hidden '\0' (NUL) byte marking where the text stops. Understanding that one convention explains almost everything else about how C strings behave — and misbehave.

Quick reference
What it is
A char array whose contents are text, terminated by a '\0' (NUL, the number zero) byte.
Mental model
A string is just an array of characters with a "stop reading here" marker at the end — every string function's real job is finding or respecting that marker.
Key numbers
A string holding N visible characters needs an array of at least N + 1 bytes — the +1 is always for the NUL terminator.
Reach for it when
Storing or manipulating text — but always with the terminator and buffer size held firmly in mind, unlike a self-tracking string type in other languages.

The NUL terminator

'\0' is a single byte with the numeric value 0 — not the character '0' (which is a completely different byte, value 48). Every C string function that walks a string — printing it, measuring its length, copying it — keeps reading bytes until it hits this one specific value, then stops.

The string "Hi!" stored as an array is actually 4 bytes: H, i, !, and a hidden NUL terminator char greeting[4] = "Hi!"; 'H' 'i' '!' '\0' [0] [1] [2] [3] — the terminator
"Hi!" looks like 3 characters but always occupies at least 4 bytes — every string literal C compiles adds this terminator automatically.

Declaring a string

char greeting[4] = "Hi!";        // explicit size — must include room for '\0'
char greeting2[] = "Hi!";        // size 4, inferred automatically from the literal
char *greeting3 = "Hi!";         // a pointer to a read-only string literal

printf("%s\n", greeting);        // %s prints characters until it hits '\0'

The first two lines create an actual, modifiable array on the stack. The third creates a pointer to a string literal that typically lives in read-only memory — attempting to modify greeting3[0] is undefined behavior, often crashing immediately on a desktop OS (and silently corrupting flash on some embedded targets).

Common string.h functions

FunctionDoesExample
strlen(s)Counts characters before the NUL (not including it)strlen("Hi!") → 3
strcpy(dst, src)Copies src into dst, including the terminatorstrcpy(buf, "Hi!")
strcat(dst, src)Appends src onto the end of dststrcat(buf, "!")
strcmp(a, b)Returns 0 if equal, nonzero otherwisestrcmp("a", "b") → negative
strncpy(dst, src, n)Like strcpy, but copies at most n bytesstrncpy(buf, src, sizeof(buf))
#include <string.h>
#include <stdio.h>

int main(void) {
    char name[20] = "Ada";
    printf("Length: %zu\n", strlen(name));   // Length: 3

    if (strcmp(name, "Ada") == 0) {
        printf("Match!\n");
    }
    return 0;
}

Reading string input safely

Reading text into a fixed-size buffer always risks overflowing it if the input is longer than expected — always give a length limit, and never trust gets() (removed from the language entirely in C11 for exactly this reason):

char name[20];
fgets(name, sizeof(name), stdin);   // reads at most 19 chars + NUL — safe

// scanf's %s is also unsafe without a width limit:
scanf("%19s", name);   // limits to 19 chars + NUL — matches the buffer size

Real-world applications

Gotchas

Field notes