Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 15

Pointer Arithmetic and In-Place Array Reversal

Recommended resources

Introduction

In our last lesson, we established the fundamental equivalence between array indexing and pointer arithmetic in C. You learned that expressions like arr[i] are essentially "syntactic sugar" for *(arr + i), and that the compiler automatically scales pointer math by the size of the data type. We also clarified the key distinction: an array name is a constant address, whereas a pointer is a modifiable variable.

Today, we will put that theory into practice. Our goal is to use pointer arithmetic to perform two essential array manipulations: traversing elements sequentially and reversing an array's contents in-place. Mastering these patterns is not just an academic exercise; it's a core competency for writing efficient, idiomatic C code that directly manipulates blocks of memory, a common requirement in game development for tasks like managing data buffers, processing sprite animations, or handling network packets.


Traversing Arrays with Pointers

In the previous lesson, we saw that we could access array elements using the *(arr + i) notation. While correct, a more common and often more efficient C idiom is to use a moving pointer that iterates directly through the array.

Instead of keeping a pointer fixed at the start and adding an offset, we can initialize a pointer to the first element and simply increment it (p++) in a loop to move to the next element. The compiler, knowing the pointer's type, handles the scaling automatically.

As this diagram illustrates, if a pointer `p` points to the first element of an integer array, `p++` advances the pointer to the next integer. The underlying address is incremented by `sizeof(int)` (typically 4 bytes), but you only need to think in terms of moving from one element to the next.

Let's look at the foundational rule of pointer arithmetic.

Pointer Arithmetic in C | C Tutorials - CODE

This article from CodeWithC provides a concise summary of how pointer arithmetic works.

Please read the section titled What is Pointer Arithmetic?. Pay close attention to the table showing how ptr + 1 moves the address by different amounts for char*, int*, and double*. This reinforces the concept of automatic scaling.

With this rule in mind, we can iterate through an array by setting a pointer to the beginning and another pointer to one element past the end. We then loop until our moving pointer reaches the end pointer.

Here is a practical exercise demonstrating this traversal.

C Programming Pointers Exercises: Beginner to Advanced ...

This set of exercises from pynative.com includes a clear example of traversing an array with pointers.

Focus on Exercise 6: Array Traversal. Study the provided solution code and its explanation. Note the two ways it presents the loop: using *(p + i) and the more idiomatic approach of incrementing the pointer itself (p++).


Pointer Operations: Addition, Subtraction, and Comparison

To effectively use pointers for traversal and other algorithms, you need to be clear on which mathematical operations are valid.

  • Addition/Subtraction of an Integer: You can add or subtract an integer from a pointer (ptr + n, ptr - n). This yields a new pointer, offset by n elements.
  • Subtraction of two Pointers: You can subtract two pointers that point into the same array (ptr2 - ptr1). This yields an integer (ptrdiff_t) representing the number of elements between them, not the number of bytes.
  • Comparison: You can compare two pointers from the same array using <, >, ==, etc. This is essential for loop conditions, such as while (ptr < end).
  • Invalid Operations: You cannot add two pointers together. This operation has no logical meaning in memory management.

The following video demonstrates the relationship between array indexing and pointer addition, and then introduces the important concept of pointer subtraction.

[Day 17] - pointer arithmetic (addition and subtraction) (and a warning with sizeof!)

Mike Shah's video provides a great hands-on demonstration of these concepts.

First, watch from the beginning to see the equivalence of data[i] and *(data + i) in action and how the pointer address changes based on the data type (int vs short). Next, watch the section on pointer subtraction from this timestamp. This part is particularly insightful. Notice how subtracting two int* pointers gives the distance in elements. The experiment where he casts the pointers to char* before subtracting to get the raw byte difference is a great low-level trick to remember.


Practical Application: Reversing an Array In-Place

Now, let's combine these concepts to implement a classic algorithm: reversing an array in-place using only pointers. "In-place" means we modify the original array without creating a copy. This is a common requirement in resource-constrained environments like game consoles or embedded systems.

The algorithm uses two pointers:

  1. A start pointer, initialized to the first element of the array.
  2. An end pointer, initialized to the last element of the array.
  3. We loop as long as start is less than end. In each iteration, we:
    a. Swap the values pointed to by start and end.
    b. Increment start (start++).
    c. Decrement end (end--).

The pointers move towards the middle of the array, swapping elements as they go. The loop terminates when they meet or cross, at which point the array is fully reversed.

The following video provides an excellent animated walkthrough of this exact algorithm. Although it uses a string (a char array), the logic is identical for an array of any type.

Reverse A String Using Pointers | C Programming Example

This video from Portfolio Courses, "Reverse A String Using Pointers," clearly illustrates the two-pointer swap algorithm.

First, watch the conceptual overview from this segment, which explains the start and end pointer strategy. Then, watch the implementation of the while loop from this part. Pay close attention to the loop condition while (start < end) and the three steps within the loop: the swap using a temp variable, start++, and end--.

Now, let's look at a clean implementation of this algorithm for an integer array.

Pointer Arithmetic in C | C Tutorials - CODE

The "Practical: Iterating with Pointers" section of the CodeWithC article contains a perfect example.

Find the function reverseArray within the code block. Read through this implementation. It directly mirrors the logic we just saw in the video but applies it to an int array.


A Note on Operator Precedence

A frequent source of bugs in C pointer code is misunderstanding operator precedence, especially with the dereference (*) and increment (++) operators. They have the same precedence and are evaluated right-to-left.

  • *ptr++ is parsed as *(ptr++). It dereferences the original pointer value, and as a side effect, increments the pointer ptr to point to the next element.
  • (*ptr)++ uses parentheses to force a different order. It dereferences the pointer ptr first, and then increments the value at that address. The pointer itself does not move.
  • *++ptr is parsed as *(++ptr). It first increments the pointer ptr to the next element, and then dereferences it to get the value of that next element.

Being mindful of these distinctions is crucial for writing correct and predictable pointer-based code. The CodeWithC article has a "Code Pitfalls" section (LINK, section 5) that you can refer to if you want to review these cases.


Conclusion

In this lesson, you've transitioned from theory to application, using pointer arithmetic to implement practical array algorithms. You now have a powerful toolset for directly manipulating sequences of data in memory, a skill that is indispensable for low-level programming.

Key Takeaways:

  • Array traversal can be efficiently performed by initializing a pointer to the start of the array and incrementing it (p++) until it reaches the end.
  • Subtracting two pointers that point to the same array yields the number of elements between them.
  • Pointer comparisons (<, >) are valid and essential for writing loop conditions.
  • The two-pointer technique (using start and end pointers moving towards the center) is a standard pattern for efficient in-place algorithms like array reversal.

In our next lesson, we will investigate a critical consequence of the pointer-array relationship known as "array decay." You will learn why passing an array to a function causes it to behave like a pointer, and why the sizeof operator can give you surprising results in this context. This will complete your foundational understanding of how arrays and pointers interact in C.