Pointers
A pointer is a variable that stores a memory address instead of an ordinary value — the location of another variable, rather than the variable itself. They're the mechanism behind everything from function arguments that can modify a caller's data to arrays, strings, and dynamic memory.
Address-of and dereference
& in front of a variable gives you its address. * in front of a pointer gives you back the value stored at the address it holds:
#include <stdio.h> int main(void) { int age = 30; int *ptr = &age; printf("age = %d\n", age); printf("&age = %p\n", (void *)&age); printf("ptr = %p\n", (void *)ptr); printf("*ptr = %d\n", *ptr); return 0; }
age = 30 &age = 0x7ffd3a2c0a3c ptr = 0x7ffd3a2c0a3c *ptr = 30
int *ptr declares ptr as a pointer to an int. &age gives its address, which is what gets stored in ptr — so ptr and &age print the same value. *ptr follows that address back to the int sitting there, giving 30. The exact address will differ every time you run the program; only the relationship matters.
Modifying a caller's variable through a pointer
C always passes arguments by value — a function gets its own copy and can't change the original. Passing a pointer instead lets the function reach back and modify whatever the pointer points at:
#include <stdio.h> void doubleIt(int *n) { *n = *n * 2; } int main(void) { int value = 21; doubleIt(&value); printf("value = %d\n", value); return 0; }
value = 42
Passing a plain int to doubleIt would only double a throwaway copy. Passing &value hands the function value's actual address, so *n = *n * 2 reaches back into main's memory and changes value itself.
Pointer arithmetic and arrays
An array's name, used on its own, decays into a pointer to its first element — which is why pointers and arrays step through memory the same way:
#include <stdio.h> int main(void) { int scores[3] = {10, 20, 30}; int *p = scores; printf("%d %d %d\n", *p, *(p + 1), *(p + 2)); return 0; }
10 20 30
p + 1 doesn't add one byte — it adds one sizeof(int), so it lands on the next element, not the next byte. That's why scores[i] and *(scores + i) mean exactly the same thing to the compiler.
NULL if it doesn't have one yet, and check for NULL before dereferencing.