What is Pointer Loops and Traversal- C Programming Tutorials For Beginners

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.

free c programming coursefree c tutorialc programming for embedded systemsembedded c programmingpointer loops in c

What You Will Learn in This Lecture

  • How to write pointer loops that run forward, in fixed steps and in reverse
  • Why p < arr + N is 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

a 3691215182124|end|
p p = a → p++ → stop when p == a + N

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_loops

Expected output:

3 6 9 12 15 18 21 24
3 9 15 21 
24 21 18 15 12 9 6 3
elements between = 8

Which elements each loop visits

forward 3691215182124
stride 2 3–9–15–21–
reverse 2421181512963 → right to left

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.

OperationResult typeAllowed?
p + n, p - npointerYes, while the result stays inside the array or one past the end
p2 - p1ptrdiff_tYes, same array only
p1 < p2, p1 == p2intYes, same array only (equality is always allowed)
p1 + p2noneNo, it does not compile

Real-World Uses in Embedded C Programming

  • **Sentinel-free buffer scan:** keep a const uint8_t *end = buf + len; and loop while (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

MistakeSymptomFix
p <= a + N as the loop testReads one element past the arrayUse < with the one-past-end address
Reverse loop p >= a; p--Undefined behaviour at the first elementUse the pre-decrement pattern from this lecture
Treating end - a as bytesOff-by-factor errorsIt 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 negativeLoop with i-- > 0 or use the pointer pattern
Comparing pointers into different arraysUnspecified resultCompare 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 const on 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 + N is a legal end marker.
  • Pointer increments scale by element size, so p += 2 moves two elements.
  • Do not form an address before the start of an array; use the --p inside 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

Leave a Reply

Your email address will not be published. Required fields are marked *