← Back to C series
🎯
Advanced
& · * · pointer arithmetic

Chapter 1 — Pointers

A pointer is a variable that **stores the address** of another variable. This is what makes C "low-level" — and what makes most C bugs.

pointer&*
Duration
1-2 hours
Level
📊 Intermediate
Prerequisite
🎯 Intermediate 4
Outcome
Read and write through addresses

What you'll learn

  • 1Read and write the address-of (`&`) and dereference (`*`) operators.
  • 2Understand pointer arithmetic on arrays.
  • 3Pass by reference using pointers.
  • 4Recognize NULL and dangling pointers.

Core Concepts

1) Declaration and basic ops

c
int x = 10;
int *p = &x;       // p holds the address of x
printf("%d\n", *p); // 10 — dereference reads the value
*p = 20;           // modify x through p
SymbolMeaning
`&x`address of x
`*p`value at p
`int *p`"pointer to int"

2) Arrays decay to pointers

c
int a[3] = {1, 2, 3};
int *p = a;        // same as &a[0]
printf("%d\n", *(p + 1));   // 2
printf("%d\n", p[1]);       // 2  (a[i] ≡ *(a+i))

3) Pointer arithmetic

c
int *p = a;
p + 1;   // advances by sizeof(int) bytes

Arithmetic is **scaled by the type size**, not raw bytes.

4) Pass by reference

c
void inc(int *p) { (*p)++; }

int x = 10;
inc(&x);
printf("%d\n", x);  // 11

C is pass-by-value; to mutate the caller's variable you pass its address.

5) NULL

c
int *p = NULL;
if (p != NULL) { ... }

Dereferencing `NULL` crashes. Always check before `*p`.

Examples

Example 1 — `ex01_basic.c`: address and dereference

c
int x = 42;
int *p = &x;
printf("x = %d\n", x);
printf("&x = %p\n", (void*)&x);
printf("p = %p\n", (void*)p);
printf("*p = %d\n", *p);

**Output**

text
x = 42
&x = 0x7fff...
p = 0x7fff...
*p = 42

Key: `p` and `&x` are the same address; `*p` reads the value at that address.

Example 2 — `ex02_swap.c`: swap two ints via pointers

c
void swap(int *a, int *b) {
    int t = *a;
    *a = *b;
    *b = t;
}
int x = 1, y = 2;
swap(&x, &y);
printf("x=%d y=%d\n", x, y);

**Output**

text
x=2 y=1

Key: passing addresses is how C does "by reference".

Example 3 — `ex03_array_ptr.c`: array via pointer

c
int a[] = {10, 20, 30};
int *p = a;
for (int i = 0; i < 3; i++) {
    printf("%d ", *(p + i));
}

**Output**

text
10 20 30

Key: `a[i]` and `*(a+i)` mean the exact same thing.

Example 4 — `ex04_ptr_arith.c`: pointer arithmetic step

c
int a[] = {10, 20, 30};
int *p = a;
printf("p   = %p\n", (void*)p);
printf("p+1 = %p\n", (void*)(p+1));
printf("diff = %ld bytes\n", (char*)(p+1) - (char*)p);

**Output**

text
p   = 0x7fff...
p+1 = 0x7fff...  (offset by 4)
diff = 4 bytes

Key: `p+1` shifts by `sizeof(int)` bytes, not 1.

Common mistakes

  1. **Uninitialized pointer** — `int *p; *p = 5;` writes to random memory.
  2. **Dangling pointer** — using a pointer after the pointee is freed/out-of-scope.
  3. **Confusing `*p++` and `(*p)++`** — different precedence.
  4. **`&p[i]` vs `p[i]`** — first is address, second is value.

Recap

  • `&` takes an address; `*` reads/writes through it.
  • Arrays decay to pointers when passed or assigned.
  • Pointer arithmetic is type-scaled.
  • Always init pointers (NULL if no target yet) and check before deref.

Try it

bash
cd src
gcc -std=c11 -Wall -o ex01 ex01_basic.c && ./ex01
gcc -std=c11 -Wall -o ex02 ex02_swap.c && ./ex02
gcc -std=c11 -Wall -o ex03 ex03_array_ptr.c && ./ex03
gcc -std=c11 -Wall -o ex04 ex04_ptr_arith.c && ./ex04

💻 Examples

Compilable, runnable examples — see the output yourself.

ex01_basic.caddress and dereference
CODE
#include <stdio.h>

int main(void) {
    int x = 42;
    int *p = &x;

    printf("x :    %d\n", x);
    printf("x :  %p\n", (void*)&x);
    printf("p :    %p   (= x )\n", (void*)p);
    printf("*p:        %d   (p  )\n", *p);

    *p = 100;
    printf("*p = 100  x = %d\n", x);
    return 0;
}
▶ Output
x = 42
&x = 0x7fff...
p = 0x7fff...
*p = 42
ex02_swap.cswap two ints via pointers
CODE
#include <stdio.h>

void swap(int *a, int *b) {
    int t = *a;
    *a = *b;
    *b = t;
}

int main(void) {
    int x = 1, y = 2;
    printf(" : x=%d, y=%d\n", x, y);
    swap(&x, &y);
    printf(" : x=%d, y=%d\n", x, y);
    return 0;
}
▶ Output
x=2 y=1
ex03_array_ptr.carray via pointer
CODE
#include <stdio.h>

int main(void) {
    int arr[5] = {10, 20, 30, 40, 50};
    int *p = arr;

    for (int i = 0; i < 5; i++) {
        printf("arr[%d]=%d, *(p+%d)=%d, p[%d]=%d\n",
               i, arr[i], i, *(p + i), i, p[i]);
    }

    printf("sizeof(arr) = %zu\n", sizeof(arr));   // 20
    printf("sizeof(p)   = %zu\n", sizeof(p));     // 8 (64-bit)
    return 0;
}
▶ Output
10 20 30
ex04_ptr_arith.cpointer arithmetic step
CODE
#include <stdio.h>

int main(void) {
    int arr[] = {100, 200, 300, 400};
    int *p = arr;

    /* p     */
    printf("p   -> %d ( %p)\n", *p, (void*)p);
    p++;
    printf("p+1 -> %d ( %p)\n", *p, (void*)p);
    p += 2;
    printf("p+3 -> %d ( %p)\n", *p, (void*)p);

    /*    =   */
    int *first = arr, *last = &arr[3];
    printf("last - first = %ld\n", (long)(last - first));
    return 0;
}
▶ Output
p   = 0x7fff...
p+1 = 0x7fff...  (offset by 4)
diff = 4 bytes

📝 Exercises

Try them yourself first, then open the solution to compare.

Exercise 1

Problem 1 (hw01.c)

Goal: Write a `swap(int *a, int *b)` that swaps two ints; demonstrate.

Requirements
  • Filename: hw01.c
Toggle solution
SOLUTION
#include <stdio.h>

static void swap(int *x, int *y) { int t = *x; *x = *y; *y = t; }

void sort3(int *a, int *b, int *c) {
    if (*a > *b) swap(a, b);
    if (*b > *c) swap(b, c);
    if (*a > *b) swap(a, b);
}

int main(void) {
    int a, b, c;
    printf(" Enter int: ");
    scanf("%d %d %d", &a, &b, &c);

    sort3(&a, &b, &c);
    printf("sorted: %d %d %d\n", a, b, c);
    return 0;
}
Exercise 2

Problem 2 (hw02.c)

Goal: Write `void double_all(int *a, int n)` that doubles every element in place.

Requirements
  • Filename: hw02.c
Toggle solution
SOLUTION
#include <stdio.h>

int sum(const int *arr, int n) {
    int s = 0;
    for (int i = 0; i < n; i++) s += arr[i];
    return s;
}

int main(void) {
    int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int n = (int)(sizeof(arr) / sizeof(arr[0]));
    printf("sum: %d\n", sum(arr, n));
    return 0;
}
Exercise 3

Problem 3 (hw03.c)

Goal: Read N ints into a dynamically sized array (use a fixed size like 100) and print sum via pointer arithmetic.

Requirements
  • Filename: hw03.c
Toggle solution
SOLUTION
#include <stdio.h>

void doubleAll(int *arr, int n) {
    for (int i = 0; i < n; i++) arr[i] *= 2;
}

int main(void) {
    int arr[] = {1, 2, 3, 4, 5};
    int n = (int)(sizeof(arr) / sizeof(arr[0]));

    doubleAll(arr, n);
    for (int i = 0; i < n; i++) printf("%d ", arr[i]);
    putchar('\n');
    return 0;
}
Example code / lecture materials

All lecture materials and example code are openly available on GitHub.

View on GitHub ↗