C Strings & Memory โ€” Quick Reference

The one-page companion to lessons on pointers, arrays, and string handling.

The One Principle. Before you write a single byte through a pointer, two things must be true:
(1) the storage behind that pointer must actually exist, and (2) there must be enough of it.
Every string bug in C is a violation of (1) or (2).

Pointer vs Array โ€” what actually exists in memory?

DeclarationWhat you getWritable?
char *p; A pointer variable (8 bytes on 64-bit). It holds an address โ€” and that's all. No characters exist. Uninitialized โ‡’ garbage address. DANGER Dereferencing is undefined behavior (UB).
char buf[100]; 100 real chars of storage on the stack. buf "decays" to char* in most expressions, but the storage is real. SAFE Write into buf (up to 100 bytes).
char *p = buf; A pointer that now points at real storage. Best of both: pointer flexibility, real backing. SAFE
char *s = "hi"; A pointer to a string literal stored in read-only memory. READ-ONLY Writing through s is UB. Use const char *.

Reading strings from input โ€” safely

โœ— The classic crash

char *s;            // points nowhere
scanf("%s", s);     // UB: writes chars to a garbage address

โœ“ Fixed: real buffer + width limit

char buf[100];
scanf("%99s", buf); // at most 99 chars + '\0' โ†’ never overflows

Why %99s? The width means "read at most 99 characters"; scanf appends the '\0', totaling 100. Always size the width to buffer_size โˆ’ 1.

โœ“ Better: a full line (spaces included)

char buf[100];
fgets(buf, sizeof buf, stdin);  // reads a line, spaces and all
// note: keeps the trailing '\n' โ€” strip it if you don't want it
buf[strcspn(buf, "\n")] = '\0';

fgets reads at most sizeof buf โˆ’ 1 chars and always null-terminates. It is the safe, boring, correct default.

<string.h> โ€” the functions, and what bites you

FunctionDoesWatch out
strlen(s) Returns length, excluding the '\0'. Argument must be null-terminated. Returns size_t, not int.
strcpy(dst, src) Copies src into dst, including '\0'. OVERFLOW If src is bigger than dst's storage โ†’ UB. dst must not overlap src.
strcat(dst, src) Appends src to the end of dst. OVERFLOW dst must have room for strlen(dst) + strlen(src) + 1. A common, silent bug.
strstr(hay, needle) Returns pointer to first needle in hay, or NULL. Check for NULL before using the result.
strcmp(a, b) Compares two strings. Returns 0 if equal. Returns 0 for equal โ€” easy to write if (strcmp(...)) by mistake. Use == 0.

Where memory lives โ€” the three regions

RegionWhat's thereLifetime
StackLocal variables, function args.Until the function returns. Pointers to these go stale after return.
Static / globalGlobals, static locals, string literals.The whole program. String literals are read-only.
Heapmalloc/calloc/realloc memory.Until you free it. You own it.
Undefined Behavior (UB) โ€” the rule, not the exception. When the standard says a program's behavior is "undefined," the compiler is allowed to assume you'd never do that โ€” and optimize accordingly. UB is not "it crashes." UB is "anything can happen," including working fine today and corrupting data tomorrow. Treat every out-of-bounds write and every dangling pointer as a correctness bug, full stop.
Read: What Every C Programmer Should Know About UB (LLVM)

Golden checklist before every scanf / strcpy / strcat

  1. Does the destination have real storage? (Array or heap, not a bare pointer.)
  2. Is it big enough? Count: existing length + incoming length + 1 for '\0'.
  3. If reading input, did I cap the width? (%99s, or use fgets.)
  4. Is the source null-terminated?