Need Help or More Information?
Questions about this free C programming course, embedded C training or career guidance? Get in touch.
Pointer Loops and Traversal
Forward, strided and safe reverse pointer loops with verified output. Free C programming course for embedded systems.
What You Will Learn in This Lecture
- How to write pointer loops that run forward, in fixed steps and in reverse
- Why
p < arr + Nis the standard end test and what the “one past the end” address means - Why the common reverse loop
for (p = arr + N - 1; p >= arr; p--)is technically undefined behaviour - A safe reverse loop that works on any array and any unsigned index type
- Pointer subtraction: how to count elements between two pointers
- How pointer traversal is used in embedded C programming for buffers and tables
Prerequisites
You need pointer arithmetic, the increment operator forms from the previous lecture and the idea that an array name decays to a pointer to its first element. All of that is covered earlier in this free C programming course.
Pointer Loops in C: Forward Traversal
A pointer loop replaces the integer index with a pointer that starts at the first element and stops when it reaches the end address. The end address is a + N, the address one element beyond the last one. C guarantees that this address can be formed and compared, even though it must never be dereferenced.
Forward traversal of an 8-element array
The loop test p < a + N is preferred over p != a + N in beginner code because it also stops if a bug moves the pointer past the end, although in correct code both are equivalent.
Stepping Through an Array in Strides
Adding more than one to the pointer skips elements. p += 2 moves two elements, not two bytes, because the compiler scales by sizeof(*p). Strided access is common when reading interleaved data, for example stereo audio samples where left and right alternate, or a sensor frame that stores X, Y, Z in turn.
There is one subtle danger. If the stride does not divide the array length evenly, the last increment can move the pointer more than one element beyond a + N. Forming such an address is undefined behaviour in the C standard even if you never dereference it. Starting at a with a stride of 2 on an 8-element array lands exactly on a + 8, which is legal. Starting at a + 1 with a stride of 3 would land on a + 10, which is not.
Warning: To be strictly portable, avoid stepping a pointer more than one element beyond the end. If the stride does not divide the length evenly, test end - p > stride before adding, or switch to an integer index for the loop control.
Reverse Traversal Without Undefined Behaviour
The tempting reverse loop starts at the last element and counts down while the pointer is at or above the start:
for (p = a + N - 1; p >= a; p--) /* looks fine, but p-- at a forms a - 1 */
use(*p);When p equals a, the final p-- produces a - 1, an address before the start of the array. The standard does not allow forming it. On many machines it happens to work, which hides the bug until the array sits at address zero or the compiler optimises the comparison away. The safe pattern starts one past the end, decrements first and tests against the start:
for (p = a + N; p != a; ) {
--p;
use(*p);
}Here p never goes below a. The pre-decrement happens inside the body, and the test p != a is checked while p is still a legal address.
Complete Example: Forward, Strided and Reverse
#include <stdio.h>
#define N 8
int main(void)
{
int a[N] = { 3, 6, 9, 12, 15, 18, 21, 24 };
int *p;
for (p = a; p < a + N; p++)
printf("%d ", *p);
printf("\n");
for (p = a; p < a + N; p += 2)
printf("%d ", *p);
printf("\n");
for (p = a + N; p != a; ) {
--p;
printf("%d ", *p);
}
printf("\n");
const int *end = a + N;
printf("elements between = %td\n", end - a);
return 0;
}gcc -std=c17 -Wall -Wextra -o ptr_loops ptr_loops.c
./ptr_loopsExpected output:
3 6 9 12 15 18 21 24
3 9 15 21
24 21 18 15 12 9 6 3
elements between = 8Which elements each loop visits
The strided loop starts at a and visits indexes 0, 2, 4 and 6, which are the values 3, 9, 15 and 21. After the last visit p becomes a + 8, exactly one past the end, so the loop stops without ever forming an illegal address. The reverse loop visits the same elements as the forward loop in the opposite order.
Counting Elements with Pointer Subtraction
Subtracting two pointers into the same array gives the number of **elements** between them, with type ptrdiff_t, not the byte distance. The last line of the program prints end - a, which is 8. Print it with %td. Subtraction is only defined when both pointers point into the same array, or one past its end.
| Operation | Result type | Allowed? |
|---|---|---|
p + n, p - n | pointer | Yes, while the result stays inside the array or one past the end |
p2 - p1 | ptrdiff_t | Yes, same array only |
p1 < p2, p1 == p2 | int | Yes, same array only (equality is always allowed) |
p1 + p2 | none | No, it does not compile |
Real-World Uses in Embedded C Programming
- **Sentinel-free buffer scan:** keep a
const uint8_t *end = buf + len;and loopwhile (p < end), which handles any length without an extra counter. - **Strided sensor frames:** step by the frame size to read the same field of each sample.
- **Backward parsing:** protocols with a trailer, such as a checksum at the end of a packet, are naturally read from the tail.
- **Circular buffers:** wrap with
if (p == end) p = start;after each increment.
Common Mistakes and Troubleshooting
| Mistake | Symptom | Fix |
|---|---|---|
p <= a + N as the loop test | Reads one element past the array | Use < with the one-past-end address |
Reverse loop p >= a; p-- | Undefined behaviour at the first element | Use the pre-decrement pattern from this lecture |
Treating end - a as bytes | Off-by-factor errors | It counts elements; multiply by sizeof *a for bytes |
Using an unsigned index to count down to zero (i >= 0) | Infinite loop, because unsigned is never negative | Loop with i-- > 0 or use the pointer pattern |
| Comparing pointers into different arrays | Unspecified result | Compare only inside one array |
Best Practices, Performance and Security
- Compute the end pointer once before the loop and compare against it; the compiler can then keep it in a register.
- Indexed and pointer loops usually compile to the same machine code at
-O2, so use whichever expresses the intent more clearly. - Use
conston the pointer target when the loop only reads, so accidental writes are rejected. - Security: bounds are the whole story. Take the length from a trusted place, never from the data being parsed, and make the end pointer a computed value rather than a guess.
- Add a static assertion on array lengths when a stride must divide them evenly.
Summary and Key Takeaways
- Use
for (p = a; p < a + N; p++)for forward traversal;a + Nis a legal end marker. - Pointer increments scale by element size, so
p += 2moves two elements. - Do not form an address before the start of an array; use the
--pinside the body pattern for reverse loops. - Subtracting pointers into one array gives an element count of type
ptrdiff_t. - Prefer integer indexes when a stride might jump more than one element past the end.
Conclusion
Pointer loops are short, fast and idiomatic, but they only stay correct if the pointer never leaves the array by more than the single permitted position. Learn the safe reverse pattern now and you avoid a bug that survives most testing. The next lecture in this free embedded C course looks at pointer operations the compiler refuses outright, which is a friendly way to remember what a pointer can and cannot do.
Frequently Asked Questions
How do I loop through an array using a pointer in C?
Set a pointer to the first element and loop while it is less than the array start plus the length, incrementing it each time: for (p = a; p < a + N; p++).
What is the one-past-the-end pointer?
It is the address just after the last element. C allows you to form and compare it, but not to dereference it.
Is for (p = a + N - 1; p >= a; p--) correct?
It is a common idiom, but at the last iteration p-- forms an address before the array start, which is undefined behaviour. Use a pre-decrement loop that stops at p == a instead.
Does p += 2 move two bytes?
No. It moves two elements. The compiler multiplies by the size of the pointed-to type.
What does subtracting two pointers return?
The number of elements between them as a ptrdiff_t. Both pointers must refer to the same array or one past its end.
Is a pointer loop faster than an index loop?
On modern compilers with optimisation, usually there is no measurable difference. Choose the form that is easier to read and verify.
Next Free Embedded C Lecture
Learn which pointer operations the compiler rejects, and why.
Need Help or More Information?
Questions about this free C programming course, embedded C training or career guidance? Get in touch.

2 Comments