Skills101

C Programming · Lesson 6 of 10 · Updated ·

Pointers in C — Addresses, Dereferencing and Pointer Arithmetic

A pointer is a variable that stores the address of another variable. That's it. Everything else follows from this one idea.

1. & and *

int x holds 10 at address 1000; int *p holds 1000, so p points to x. &x is 1000, p is 1000 and *p is 10; *p = 25 changes x

  • &x — "address of x"
  • int *p — "p is a pointer to an int"
  • *p — "the value at the address in p" (dereferencing)
#include <stdio.h>

int main(void) {
    int x = 10;
    int *p = &x;
    printf("%d %d\n", x, *p);
    *p = 25;                 /* change x through p */
    printf("%d\n", x);
    printf("%d\n", p == &x);
    return 0;
}
10 10
25
1

(Actual addresses change every run, so we compare them instead of printing them.)

2. Pointers and arrays

Array a holds 10, 20, 30, 40, 50 at addresses 100, 104, 108, 112, 116; a + 2 is 108 and *(a + 2) equals a[2], which is 30

The name of an array is (in most expressions) a pointer to its first element. And a[i] is exactly *(a + i).

#include <stdio.h>

int main(void) {
    int a[5] = {10, 20, 30, 40, 50};
    int *p = a;                       /* same as &a[0] */
    printf("%d %d %d\n", *p, *(p + 2), p[4]);
    p++;                              /* move to the next int */
    printf("%d\n", *p);
    printf("%d\n", (int)(&a[4] - &a[0]));   /* distance in elements */
    return 0;
}
10 30 50
20
4

Pointer arithmetic

p + 1 moves by sizeof(type) bytes, not 1 byte. For an int * that's 4 bytes; for a double *, 8 bytes. You can:

  • add/subtract an integer (p + 2, p--)
  • subtract two pointers into the same array (gives the number of elements between them)
  • compare pointers

You can't add two pointers.

3. NULL and safety

int *p = NULL;      /* points nowhere */
if (p != NULL) {
    printf("%d", *p);
}
  • Dereferencing NULL crashes the program (segmentation fault).
  • A wild pointer is uninitialised (points anywhere) — always initialise pointers.
  • A dangling pointer points to memory that was freed or a local variable that no longer exists.

4. Pointer to pointer

#include <stdio.h>

int main(void) {
    int x = 7;
    int *p = &x;
    int **pp = &p;
    printf("%d %d %d\n", x, *p, **pp);
    **pp = 99;
    printf("%d\n", x);
    return 0;
}
7 7 7
99

Used for dynamic 2D arrays and when a function must change a pointer (e.g. inserting at the head of a linked list).

5. const and pointers

DeclarationCan change the value?Can point elsewhere?
const int *p✗✓
int *const p✓✗
const int *const p✗✗

Read it right to left: int *const p = "p is a const pointer to int".

6. void pointers

void * can hold the address of any type (used by malloc). You must cast it to a real type before dereferencing.

Common mistakes

  • Using *p before p points to valid memory.
  • Confusing *p++ (move p, value of old position) with (*p)++ (increase the value).
  • Returning the address of a local variable from a function (dangling pointer).

Quick recap

  • &x = address; *p = value at address; int *p declares a pointer.
  • a[i] == *(a + i); p + 1 moves by sizeof(type).
  • Initialise pointers; check for NULL; avoid dangling pointers.
  • **pp = pointer to pointer; read const declarations right to left.

Practice what you learned

📝 Quiz: C Pointers5 questions · instant answers & explanations · +10 XP · counts towards your free certificateTake the quiz →