Pointer Foundations
Memory as boxes, &, declaring pointers, *, initializing, garbage-when-uninitialized.
Six pieces, and this is where the mental model either clicks or doesn't: memory as a row of addressable boxes, & to get an address, how to declare a pointer, * to dereference, initializing one properly, and what happens when I don't.
Memory as boxes
Every byte in memory has its own address, like a house number. A variable is really just a label the compiler attaches to one of those addresses. A pointer is a variable whose entire job is to store one of those addresses instead of an ordinary value.
int x = 10;
int *p = &x;
printf("%d\n", x); /* 10 — the value */
printf("%p\n", (void *)&x); /* 0x7ffee... — the address */
printf("%p\n", (void *)p); /* same address — p stores it */
printf("%d\n", *p); /* 10 — dereferencing p gets back to the value */Declaring vs dereferencing
int *p reads as "p is a pointer to int" when declaring. The same * used later, *p, means "go to the address p holds and get the value there" — same symbol, two different jobs depending on context.
Garbage when uninitialized
int *p; with no initializer holds whatever address happened to already be sitting in that memory — not NULL, not zero, just garbage. Dereferencing it reads or writes to a random address, which might crash immediately or might silently corrupt something else entirely. A pointer gets initialized, every time, even if it's just to NULL.
Notes from readers
Comments — via GitHub