Skip to main content

Welcome to a Grasp lesson

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

Lesson 14

Arrays and Pointers: An Equivalence

Recommended resources

Introduction

In our last lesson, we focused on pointer safety, establishing the critical habits needed to avoid uninitialized, null, and dangling pointers. Now that we have a solid grasp of how to handle pointers safely, we can explore one of their most fundamental and powerful roles in C: their intimate relationship with arrays.

Today's lesson will unravel the deep connection between array indexing and pointer arithmetic. You will learn that the familiar square-bracket notation, array[i], is merely a convenient abstraction—syntactic sugar—for pointer operations. Mastering this concept is essential for writing efficient, idiomatic C, and it forms the basis for many advanced techniques you'll need for performance-sensitive applications like game engines and emulators.


The Equivalence of Arrays and Pointers

At the heart of today's topic is a simple but profound rule in C: in most expressions, the name of an array "decays" into a pointer to its first element. This means that if you have an array int arr[10], using arr in your code is equivalent to taking the address of its first element, &arr[0].

Because of this, you can access any element in the array using either standard array indexing or by using the array name as a pointer. The two syntaxes are interchangeable:

  • arr[i] is equivalent to *(arr + i)

Let's visualize this relationship.

This diagram shows how an array in memory is a contiguous block of elements. An array name like `arr` or a pointer like `ptr` can serve as a base address. Adding an integer `i` to this base pointer effectively moves the reference `i` elements forward in memory.

To solidify this core concept, let's turn to a clear textual explanation.

Advanced Pointers - Techno-Plaza

This article from Techno-Plaza directly explains the relationship between array indexing and pointer arithmetic.

Please read the first half of Step 2 - Pointer Arithmetic and Multiple Indirection. Focus on the section that begins with this paragraph. The key takeaway is understanding how *(array + 12) and array[12] result in the same value. You can disregard the discussion on multi-dimensional arrays for now; we'll focus on the single-dimension case first.


How Pointer Arithmetic Works

You might be wondering: if a pointer is just a memory address (an integer), how does adding 1 to it correctly move to the next int in an array, which might be 4 bytes away?

This is where the C compiler performs a crucial service. When you perform arithmetic on a pointer, the compiler automatically scales the operation by the size of the data type the pointer points to.

  • If p is an int* and sizeof(int) is 4, then p + 1 calculates the address p + (1 * 4).
  • If d is a double* and sizeof(double) is 8, then d + 3 calculates the address d + (3 * 8).

This automatic scaling is what makes pointer arithmetic so powerful and intuitive for navigating arrays of any type. The following video provides an excellent summary of this mechanism.

Master Pointer Arithmetic In 10 Minutes (The Ultimate Guide For C Programmers).

This video from HuwsTube, "Master Pointer Arithmetic In 10 Minutes," clearly explains the scaling mechanism and the "syntactic sugar" concept.

Watch the segment from this timestamp. Pay close attention to two key ideas: How adding 1 to an int pointer actually adds sizeof(int) (typically 4) to the underlying memory address. The statement that array indexing is "no more than syntactic sugar" for pointer arithmetic.

A Common Pitfall

Because the compiler handles this scaling for you, a common mistake for beginners is to try to "help" the compiler by manually multiplying by the size of the type. This leads to incorrect results, as the compiler will apply its scaling on top of your manual scaling.

The next video demonstrates this exact mistake and then shows the correct, simpler approach.

you will never ask about pointer arithmetic after watching this video

The channel Low Level provides a great practical demonstration of the right and wrong way to increment a pointer through an array of structs.

Please watch from this section. Notice how the incorrect code, p_person += sizeof(struct person), leads to a crash, while the correct code is simply p_person += 1. The compiler knows you mean "move to the next person struct," not "move by one byte."


So, Are They Identical?

We've established that arr[i] and *(arr + i) are equivalent operations. But this doesn't mean arrays and pointers are identical entities. There is a critical difference:

  • An array name is a constant. It refers to a fixed memory location where the array begins. You cannot change where an array is located.
  • A pointer is a variable. It stores a memory address, and you can change the address it stores.

This has a direct practical consequence: operations like ptr++ or ptr = another_address are perfectly legal for a pointer variable. However, the equivalent operations on an array name, such as arr++ or arr = another_address, are illegal and will cause a compile error. The array's location is fixed.

int my_array[10];
int* my_ptr = my_array; // Point my_ptr to the start of the array

my_ptr++; // LEGAL: my_ptr now points to my_array[1]

my_array++; // ILLEGAL: Cannot modify the address of an array

This distinction is subtle but fundamental to C mastery. The following article provides an excellent deep dive into this topic.

Are pointers and arrays equivalent in C? - Eli Bendersky's website

Eli Bendersky's well-regarded article explores the nuances of this topic.

Please read two sections from this article: Start with So how are they different?. The diagrams provide a superb visual explanation of how the compiler treats an array name as a fixed label versus a pointer as a variable holding an address. Then, read the section Does the difference affect me?, which highlights the practical implication that array names are not modifiable variables.


Conclusion

Today, you've learned one of C's most important concepts: the interchangeability of array indexing and pointer arithmetic. This isn't just a theoretical curiosity; it's the mechanism that underlies much of the C standard library (especially string manipulation) and is key to writing efficient, low-level code.

Key Takeaways:

  • In most contexts, an array's name decays into a pointer to its first element.
  • Array access array[i] is syntactic sugar for the pointer operation *(array + i).
  • Pointer arithmetic is automatically scaled by the size of the pointed-to data type. ptr + 1 moves the pointer to the next element in the array, regardless of its size.
  • The primary difference between an array and a pointer is that an array's name is a constant address, while a pointer is a variable that stores an address. You can increment a pointer, but you cannot increment an array name.

In our next lesson, we will explore a direct consequence of this "array decay" behavior. You'll learn why the sizeof operator can sometimes return unexpected results when used with arrays, particularly when they are passed to functions, and how to reliably manage array lengths in your programs.