Code of the Day
IntermediatePointers

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.

CIntermediate12 min read
Recommended first
By the end of this lesson you will be able to:
  • 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:

  1. Modifying caller variables (you saw this with swap in the functions module).
  2. Working with arrays efficiently — array names are pointers to their first element.
  3. Dynamic memory allocationmalloc returns 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.

Finished reading? Mark it complete to track your progress.

On this page