What is a pointer?
Learn what pointers are in C — memory addresses, the address-of and dereference operators, and why pointers are the core of C's power.
- Explain that a pointer is a variable that holds a memory address
- Use the address-of operator & to get a variable's address
- Use the dereference operator * to access the value at an address
- Declare a pointer variable with the correct type syntax
Of all the features that distinguish C from higher-level languages, pointers are the most important and the most misunderstood. A pointer is simply a variable that holds a memory address. That's it. But because every variable, array, function, and struct in a running program has an address, pointers give you the ability to work with the underlying layout of memory directly — and that is what makes C both powerful and dangerous.
Every variable lives at an address
When you write int x = 42;, the runtime allocates space for an int (4 bytes on a 32- or 64-bit system) somewhere in memory and stores the value 42 there. That location has an address — a number representing where in the byte-addressable memory space those 4 bytes are.
#include <stdio.h>
int main(void) {
int x = 42;
printf("Value of x: %d\n", x);
printf("Address of x: %p\n", (void *)&x);
return 0;
}Output (addresses vary per run):
Value of x: 42
Address of x: 0x7ffee3a5c8bc&x is the address-of operator applied to x. It gives you the address where x is stored. The %p format specifier prints a pointer in hexadecimal.
Declaring a pointer variable
A pointer is a variable whose value is an address. Declare it by appending * to the type:
int x = 42;
int *p; /* p is a pointer to int */
p = &x; /* p now holds the address of x */Read int *p as "p is a pointer to int." The type int * means "the thing p points to is an int."
The dereference operator
*p when p is a pointer means "the value at the address p holds" — this is dereferencing:
int x = 42;
int *p = &x;
printf("p = %p\n", (void *)p); /* the address */
printf("*p = %d\n", *p); /* the value at that address -- 42 */
*p = 100; /* write 100 to the address p holds -- modifies x */
printf("x = %d\n", x); /* now 100 */p holds an address. *p holds what is at that address. Modifying *p modifies the original variable.
NULL — the absent pointer
A pointer that does not point to anything should be set to NULL:
int *p = NULL; /* p points to nothing */
if (p != NULL) {
printf("%d\n", *p); /* safe -- only dereference if not NULL */
}Dereferencing NULL is a segmentation fault — the OS kills the process because address 0 is not mapped to any valid memory. Always check for NULL before dereferencing a pointer that might not be valid.
What pointers enable
Pointers unlock three capabilities that are impossible without them:
- Modifying caller variables (you saw this with
swapin the functions module). - Working with arrays efficiently — array names are pointers to their first element.
- Dynamic memory allocation —
mallocreturns a pointer to heap memory.
#include <stdio.h>
void increment(int *n) {
(*n)++; /* increment the value at address n */
}
int main(void) {
int count = 0;
increment(&count);
increment(&count);
increment(&count);
printf("count = %d\n", count); /* 3 */
return 0;
}Without the pointer, increment would receive a copy of count and the original would stay at 0.
Common pointer confusion
The * in a declaration vs. in an expression:
int *p = &x; /* declaration: p is a pointer to int */
*p = 5; /* expression: write 5 to the address p holds */Same character, two different meanings. In a declaration, * is part of the type syntax. In an expression, * is the dereference operator.
A pointer has its own address too:
int x = 42;
int *p = &x;
int **pp = &p; /* a pointer to a pointer */
printf("pp = %p\n", (void *)pp); /* address of p */
printf("*pp = %p\n", (void *)*pp); /* value of p = address of x */
printf("**pp = %d\n", **pp); /* value of x = 42 */Where to go next
Next: pointer arithmetic — adding and subtracting integers from pointers to move through memory, which is how C iterates over arrays at the machine level.
Lab: Palindrome checker
Write a C program that checks whether a string is a palindrome — practising array iteration, string manipulation, and careful null-terminator handling.
Pointer arithmetic
Add and subtract integers from pointers to navigate memory — understanding how the compiler scales pointer arithmetic by the element type size.