Pointers

Course 1 · Ch 7
Pointers
What Rust's borrow checker exists, specifically, to prevent

Chapter 5 needed a pointer to let a function modify a caller's variable. Chapter 6's arrays turned out to already secretly be pointers. This chapter finally names the mechanism directly — and closes the loop this whole course opened back in Chapter 1.

What a Pointer Actually Is

A pointer is a variable whose value is a memory address. & (address-of) gets a variable's address; * (dereference) accesses the value stored at an address.

int x = 42; int *p = &x; // p holds x's address printf("%d\n", *p); // *p dereferences p — prints 42 *p = 100; // writes through the pointer — x is now 100

Why C Needs Pointers

  • Simulating pass-by-reference — Chapter 5's own unsolved problem: pass &x instead of x, and the function can modify the caller's variable through the pointer
  • Working with arrays — Chapter 6's decay is pointer usage; every array access secretly goes through this exact mechanism
  • Dynamic memory — Course 2's central chapter; memory allocated at runtime is only ever reachable through a pointer
void increment(int *p) { *p = *p + 1; // modifies the caller's actual variable } int n = 5; increment(&n); // n is now 6 — Chapter 5's limitation, solved

Pointer Arithmetic

p + 1 doesn't advance by one byte — it advances by sizeof the pointed-to type. This is exactly what makes array indexing work: arr[i] is literally defined as *(arr + i), the same operation spelled two different ways.

int arr[3] = {10, 20, 30}; int *p = arr; printf("%d\n", *(p + 1)); // 20 — identical to arr[1]

The Null Pointer & Dereferencing It

NULL represents "points at nothing." Dereferencing a null (or uninitialized) pointer is undefined behavior — typically a crash, but never guaranteed. Rust's safe code has no null pointers at allOption<T> replaces the entire concept, forcing an explicit check before any value can be used, eliminating this bug category by design rather than by convention.

What Rust's Borrow Checker Exists to Prevent

Here's the real payoff. A dangling pointer is a pointer to memory that's already been freed, or has gone out of scope — the pointer still looks perfectly valid, but what it points to is gone. C lets you create and use one freely; it's simply undefined behavior. Rust's borrow checker makes this a compile error — the program literally won't build if a reference could ever outlive the data it points to. This is the exact mechanism Rust's own course named as its founding goal back in rust1-1, and it's this specific bug class it exists to eliminate.

ConceptRustC
Null valuesno null — Option<T>, checked explicitlyNULL — dereferencing it is undefined behavior
Dangling referencescompile error — the borrow checker refuses to buildundefined behavior — compiles and runs, may crash later or corrupt memory
Pointer arithmeticnot available on safe referencesfreely available — scales by the pointed-to type's size
Always initialize a pointer
An uninitialized pointer holds garbage — some leftover address from whatever was in that memory before. Dereferencing garbage is one of the most common real sources of crashes. Initialize every pointer, even to NULL, the moment it's declared.
Never return the address of a local variable
A local variable's memory is only valid while its function is running. Returning &local_var hands the caller a pointer to memory that's already gone the instant the function returns — a classic dangling-pointer bug, and precisely the class of error Rust's borrow checker refuses to compile.

Coding Challenges

Challenge 1

Declare an int variable, a pointer to it, print the value through the pointer, then modify the value through the pointer and print the original variable directly to confirm it changed.

📄 View solution
Challenge 2

Write a function swap(int *a, int *b) that swaps the values two pointers point to. Call it from main with two variables and print both before and after to prove the swap worked.

📄 View solution
Challenge 3

Explain, precisely, what a dangling pointer is, why C allows creating and using one, and why Rust's borrow checker refuses to compile a program that could ever produce one.

📄 View solution

Chapter 7 Quick Reference

  • & — address-of; * — dereference (also used in a declaration to mean "this is a pointer")
  • Pointers solve pass-by-reference, array access, and (Course 2) dynamic memory
  • Pointer arithmetic scales by the pointed-to type's size — arr[i] is literally *(arr + i)
  • NULL — dereferencing it is undefined behavior; Rust's Option<T> removes null entirely
  • Dangling pointer — points to freed/out-of-scope memory; UB in C, a compile error in Rust
  • Never return the address of a local variable
  • Next chapter: strings — char arrays, null termination, and the classic buffer-overflow risk