Memory, Pointers, and File I/O
Master low-level memory control, pointer mechanics, and persistent storage.
Content
Pointer Arithmetic
Versions:
Watch & Learn
AI-discovered learning video
Sign in to watch the learning video for this topic.
Pointer Arithmetic — Walking the Memory Like a Boss
This is the spot where pointers stop being mysterious addresses and start behaving like powerful, slightly dangerous tools.
Hook: Why pointer arithmetic matters (and why your future self will thank you)
You already know how pointers store addresses and how the stack vs heap organizes memory. Now imagine you have a treasure map (an array) and a scout (a pointer). Pointer arithmetic is how the scout moves across the map, one step at a time, but each step is scaled to the size of the terrain. Get this right and you traverse memory fast and expressively; get it wrong and you walk off a cliff called undefined behavior.
In this lesson we build on: pointers and addresses, memory layout (stack vs heap), and algorithm efficiency from recursion. We will see how pointer arithmetic helps write tight, efficient loops and recursive traversals without extra indexing overhead.
What is pointer arithmetic? (Short definition)
- Pointer arithmetic means performing arithmetic operations on pointer values to move them across memory.
- In C, adding 1 to a pointer moves it forward by the size of the pointed-to type (not by one byte).
Micro explanation
If int is 4 bytes on your machine, p + 1 where p is int * moves forward 4 bytes; char * moves forward 1 byte.
Rules of the road: the formal bits you will thank me for later
- Pointer arithmetic scales by
sizeof(type). Sop + nmoves byn * sizeof(*p)bytes. - You can add or subtract integers to/from pointers:
p + 3,p - 2. - You can subtract two pointers of the same array to get distance:
p2 - p1yields aptrdiff_tmeasured in elements. - Comparisons (
<,>,==) are defined only for pointers to elements of the same array (or one past the last element). - Pointer arithmetic outside the owning array (except the one-past-the-end) is undefined behavior. Be safe.
- Pointer arithmetic on
void *is not standard C (GNU allows it as a byte-pointer), so avoid unless you mean it.
Quick real-world analogy
Think of memory as a bookshelf. Each book has a width (type size). A pointer is your index finger on a book. When you move your finger two books to the right, you moved by two book widths, not two millimeters.
Examples (because code is how you learn): iterating arrays, pointer subtraction, and structs
1) Iterating an array with pointers vs indices
Code: iterating with an index
int arr[] = {1, 2, 3, 4, 5};
for (size_t i = 0; i < 5; i++)
{
printf("%d\n", arr[i]);
}
Code: iterating with pointer arithmetic
int *p = arr; // points to arr[0]
int *end = arr + 5; // one past last element
for (; p < end; p++)
{
printf("%d\n", *p);
}
Why it matters: pointer loop avoids indexing calculation arr + i on each iteration and is idiomatic C. The CPU cost is typically the same or slightly better, and the code expresses intent: walking memory sequentially.
2) Pointer subtraction to measure distance
int *a = &arr[1];
int *b = &arr[4];
ptrdiff_t dist = b - a; // dist == 3
This gives the number of elements between pointers, not bytes.
3) Pointer arithmetic with structs
struct Node { int x; double d; } nodes[10];
struct Node *p = nodes;
p += 2; // moves by 2 * sizeof(struct Node)
Pointer arithmetic respects alignment and struct layout automatically.
Pointer arithmetic and recursion: a practical pattern
When you wrote recursive algorithms you considered time and space complexity. Pointer arithmetic lets you write recursive traversals without extra indexing variables, often reducing space slightly and making each recursive call focus on the local pointer window.
Example: recursively print an array
void print_recursive(int *p, size_t n)
{
if (n == 0) return;
printf("%d\n", *p);
print_recursive(p + 1, n - 1);
}
This is tidy, avoids an index parameter, and shows how recursion and pointer arithmetic combine naturally. Complexity: still O(n) time and O(n) stack space unless you tail-optimize, but pointer arithmetic keeps each frame small.
Performance note: O(1) operations, cache-friendly traversal
Pointer arithmetic itself is O(1). The bigger performance win is that pointer-based traversal typically produces sequential memory access, which is cache-friendly. Sequential memory access beats random access in real-world speeds, so pointers + arrays = usually fast loops.
Common pitfalls (aka the landmines) — learn these now
- Off-by-one errors: iterating to
<=last element? Danger. Preferp < endand useend = start + length. - Crossing object boundaries: comparing or subtracting pointers from different arrays is undefined.
- Pointer arithmetic on
void *: not standard; cast tochar *oruint8_t *to do byte-wise moves. - Misaligned accesses: casting pointers to the wrong type and dereferencing can cause alignment faults on some architectures.
- Using freed pointers: pointer arithmetic cannot resurrect safety. If memory was freed, any arithmetic or dereference is UB.
Quick cheatsheet table
| Operation | Example | Meaning |
|---|---|---|
| Move forward | p + 1 |
Next element (sizeof(*p) bytes) |
| Move backward | p - 2 |
Two elements before |
| Distance | q - p |
Elements between p and q (ptrdiff_t) |
| Compare | p < q |
Only valid inside same array |
Closing: key takeaways (read these three times)
- Pointer arithmetic moves by elements, not bytes — scaled by the pointed type.
- Only do arithmetic inside the same array or the one-past-the-end pointer — outside that, behavior is undefined.
- Pointer arithmetic + recursion = clean code for array traversals, but watch stack space.
Final memorable insight: pointer arithmetic is like having a GPS for memory — it tells you how many addresses to skip in human-sized steps (elements). Learn the rules, respect the bounds, and you'll traverse memory quickly and elegantly. Mess up the rules and you'll get a segfault — which, in systems programming, is the universe's polite way of saying, try again.
If you want, I can now show live examples: converting a recursive array-sum to an iterative pointer-based loop and analyze its time and space tradeoffs. Want that?
Comments (0)
Please sign in to leave a comment.
No comments yet. Be the first to comment!