Pointers
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.
Why C Needs Pointers
- Simulating pass-by-reference — Chapter 5's own unsolved problem: pass
&xinstead ofx, 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
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.
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 all — Option<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.
| Concept | Rust | C |
|---|---|---|
| Null values | no null — Option<T>, checked explicitly | NULL — dereferencing it is undefined behavior |
| Dangling references | compile error — the borrow checker refuses to build | undefined behavior — compiles and runs, may crash later or corrupt memory |
| Pointer arithmetic | not available on safe references | freely available — scales by the pointed-to type's size |
NULL, the moment it's declared.
&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
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 solutionWrite 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 solutionExplain, 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 solutionChapter 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'sOption<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