Question

Why `a[5]` Equals `5[a]` in C: Array Indexing and Pointer Arithmetic Explained

carrayspointerspointer-arithmetic

Question

In C, why does a[5] evaluate to the same thing as 5[a]?

As discussed in The C Programming Language and mentioned in the Stack Overflow podcast, this behavior is often explained as a result of pointer arithmetic. I understand that this is a property of arrays in C, but I do not yet understand why the two expressions are equivalent.

For example:

int a[] = {10, 20, 30, 40, 50, 60};

printf("%d\n", a[5]);
printf("%d\n", 5[a]);

Why do both expressions access the same element?

Short Answer

By the end of this page, you will understand how C array indexing is defined, why a[i] is really shorthand for *(a + i), and why that makes a[5] and 5[a] equivalent. You will also see how this relates to pointers, arrays, memory addresses, and common mistakes beginners make when working with them.

Concept

In C, the array subscript operator [] is defined in terms of pointer arithmetic.

The key rule is:

a[i]  ==  *(a + i)

This means:

  • a refers to the starting address of the array's first element in most expressions
  • i is an offset
  • a + i means “move forward i elements”
  • *(a + i) means “read the value at that computed address”

Because addition is commutative, these two expressions are equivalent:

a + i
i + a

So:

a[i] == *(a + i)
     == *(i + a)
     == i[a]

That is why a[5] and 5[a] access the same element.

Why this matters

This is important because arrays and pointers are closely related in C:

  • arrays often decay to pointers in expressions
  • pointer arithmetic is scaled by the size of the pointed-to type
  • indexing syntax is just a convenient way to use pointer offsets

Understanding this helps you read C code correctly and avoid memory bugs.

Important clarification

This does not mean arrays and pointers are exactly the same thing.

For example:

  • an array has a fixed size as part of its type
  • a pointer is a variable that stores an address

But when you use an array name in many expressions, it behaves like a pointer to its first element. That is the reason indexing works this way.

Mental Model

Think of an array like a row of mailboxes.

  • a is the location of the first mailbox
  • 5 means “move 5 boxes forward”
  • *(a + 5) means “open the mailbox 5 positions after the first one”

Now imagine giving directions:

  • “start at a, move 5”
  • “move 5 from a”

Both describe the same destination.

That is why:

a[5]

and

5[a]

lead to the same mailbox.

The [] operator in C is really just a convenient way of saying “go to this base address, then move by this offset, then dereference.”

Take Quiz

Syntax and Examples

The core indexing rule in C is:

x[y] == *(x + y)

That means either side of [] participates in address calculation.

Basic example

#include <stdio.h>

int main(void) {
    int a[] = {10, 20, 30, 40, 50, 60};

    printf("a[5] = %d\n", a[5]);
    printf("5[a] = %d\n", 5[a]);

    return 0;
}

Output:

a[5] = 60
5[a] = 60

Both print the same value.

Equivalent forms

int value1 = a[2];
int value2 = *(a + 2);
int value3 = *(2 + a);
int value4 = 2[a];

All four read the same element.

With a pointer

#include <stdio.h>

int main(void) {
    int a[] = {100, 200, 300};
    int *p = a;

    printf("%d\n", p[1]);
    printf("%d\n", *(p + 1));
    printf("%d\n", 1[p]);

    return 0;
}

Here too, all expressions refer to the second element.

Why pointer arithmetic works correctly

If a points to int, then a + 1 does not move by 1 byte. It moves by sizeof(int) bytes.

So if a starts at address 1000 and sizeof(int) is 4:

  • a + 0 -> address 1000
  • a + 1 -> address 1004
  • a + 2 -> address 1008

That scaling is built into pointer arithmetic.

Step by Step Execution

Consider this example:

#include <stdio.h>

int main(void) {
    int a[] = {11, 22, 33, 44, 55, 66};
    int result = 5[a];
    printf("%d\n", result);
    return 0;
}

Step-by-step

1. The array is created

int a[] = {11, 22, 33, 44, 55, 66};

Memory conceptually looks like this:

IndexValue
011
122
233
344
455
566

2. Evaluate 5[a]

By the C rule for subscripting:

5[a] == *(5 + a)

3. Reorder the addition

Since addition gives the same result here:

*(5 + a) == *(a + 5)

4. Compute the address

a + 5 means:

  • start at the first element of a
  • move forward 5 int positions

That lands on the element with index 5.

5. Dereference the address

*(a + 5)

reads the value stored there, which is:

66

6. Store and print

int result = 66;
printf("%d\n", result);

Output:

66

So 5[a] is not a special trick built into arrays. It is just the direct result of how [] is defined in C.

Real World Use Cases

Most programmers do not write 5[a] in production code, because it is confusing. But the idea behind it appears everywhere.

1. Accessing array elements

int nums[] = {4, 8, 15, 16, 23, 42};
int x = nums[3];

This is really pointer arithmetic under the hood.

2. Iterating through buffers

char message[] = "hello";
for (int i = 0; message[i] != '\0'; i++) {
    printf("%c\n", message[i]);
}

Each message[i] is *(message + i).

3. Working with strings

C strings are character arrays, so indexing is extremely common:

char *name = "Alice";
printf("%c\n", name[1]);

4. Parsing binary data

Programs that process files, network packets, or memory buffers often rely on pointer offsets.

unsigned char packet[8];
unsigned char header = packet[0];
unsigned char flag = packet[3];

5. Function parameters that receive arrays

void print_first(int arr[]) {
    printf("%d\n", arr[0]);
}

In function parameters, arr[] is treated like a pointer parameter, which is another reason this concept matters.

Take Quiz

Real Codebase Usage

In real C codebases, developers rely on indexing and pointer arithmetic in practical, readable ways.

Common patterns

Guarding bounds before indexing

int get_value(int *arr, int length, int index) {
    if (index < 0 || index >= length) {
        return -1;
    }
    return arr[index];
}

This avoids out-of-bounds access.

Iterating with indexes

for (int i = 0; i < length; i++) {
    total += arr[i];
}

This is usually clearer than writing explicit pointer arithmetic.

Iterating with pointers

for (int *p = arr; p < arr + length; p++) {
    total += *p;
}

This is equivalent in spirit, and sometimes preferred in low-level code.

Using early validation

int read_char(const char *text, int index) {
    if (text == NULL || index < 0) {
        return -1;
    }
    return text[index];
}

Buffer processing

for (size_t i = 0; i < size; i++) {
    buffer[i] = 0;
}

In real projects, developers usually write the readable form buffer[i], even though *(buffer + i) is equivalent.

Style note

Even though 5[a] is valid C, it is almost never used intentionally in professional code because it hurts readability. Knowing why it works is useful; writing it regularly is not.

Common Mistakes

1. Thinking arrays and pointers are identical

They are related, but not the same.

int a[10];
int *p = a;
  • a is an array of 10 integers
  • p is a pointer to int

They behave similarly in many expressions, but they are different types.

2. Forgetting that indexing is pointer arithmetic

Some beginners think a[i] is special syntax only for arrays. But pointers can be indexed too:

int *p = a;
printf("%d\n", p[2]);

This works because p[2] means *(p + 2).

3. Going out of bounds

int a[3] = {1, 2, 3};
printf("%d\n", a[5]);  // wrong

This is undefined behavior.

Avoid it by checking indexes carefully.

4. Assuming a + 1 means one byte later

This is wrong:

int *p = a;
p = p + 1;

This moves by one int, not one byte.

5. Using 5[a] for cleverness

This is legal:

printf("%d\n", 2[a]);

But it is poor style in most code. Prefer the standard readable form:

printf("%d\n", a[2]);

6. Confusing dereferencing with indexing

These are equivalent for one element access:

a[3]
*(a + 3)

But this is different:

*a + 3

That means:

  • read the first element of a
  • then add 3 to its value

Not the same as accessing index 3.

Broken example

int a[] = {10, 20, 30};
printf("%d\n", *a + 2);   // prints 12, not 30
printf("%d\n", *(a + 2)); // prints 30

Comparisons

ConceptMeaningExampleNotes
a[i]Element at index ia[3]Standard readable form
*(a + i)Dereference after pointer offset*(a + 3)Exactly equivalent to a[i]
i[a]Same as a[i]3[a]Valid but unusual
*a + iFirst element value plus i*a + 3Not indexing

Arrays vs pointers

FeatureArrayPointer
StoresActual elementsAn address
Size is part of typeYesNo
Can be reassignedNoYes
Can use []YesYes
Decays to pointer in many expressionsYesNot applicable

Indexing vs explicit pointer style

StyleExampleWhen used
Indexingarr[i]Most common and readable
Pointer arithmetic*(arr + i)Low-level code, teaching, special cases
Pointer iterationfor (p = arr; p < arr + n; p++)Performance-sensitive or systems code
Take Quiz

Cheat Sheet

x[y] == *(x + y)

Core rules

  • a[i] means element i from base a
  • a[i] is exactly the same as *(a + i)
  • therefore i[a] is also valid
  • pointer arithmetic moves in units of the pointed-to type
  • a + 1 for int *a moves by sizeof(int) bytes

Examples

int a[] = {10, 20, 30};

a[1];      // 20
*(a + 1);  // 20
1[a];      // 20

Not the same

*a + 1     // first element plus 1
*(a + 1)   // second element

Remember

  • arrays and pointers are closely related, but not identical
  • 5[a] is valid C, but avoid using it for readability
  • never index outside array bounds

Safe habit

Prefer:

a[i]

instead of:

i[a]

FAQ

Why is 5[a] valid in C?

Because array subscripting is defined as *(a + i). Since a + i and i + a are equivalent, 5[a] means the same as a[5].

Is 5[a] good style?

No. It is valid, but unusual and confusing. Use a[5] in normal code.

Does this only work for arrays?

No. It also works for pointers:

int *p = a;
p[2];
2[p];

Are arrays and pointers the same in C?

Not exactly. Arrays and pointers are different types, but array names often decay to pointers in expressions.

Why does a + 1 move by one element instead of one byte?

Because pointer arithmetic is scaled by the size of the pointed-to type.

What does *(a + i) mean?

It means: start at address a, move forward i elements, then read the value stored there.

Can I use negative indexes with pointers?

Only if the resulting address still refers to a valid element within the same array object. Otherwise, the behavior is undefined.

Is this behavior unique to C?

It is most famously discussed in C, and languages derived from C may inherit similar rules at a low level, but many higher-level languages hide this entirely.

Take Quiz

Mini Project

Description

Build a small C program that explores array indexing and pointer arithmetic side by side. The program will print values using normal indexing, pointer arithmetic, and reversed indexing such as 2[a]. This helps make the rule x[y] == *(x + y) concrete and visible.

Goal

Create a program that proves several equivalent forms of array access produce the same result.

Requirements

  • Declare an integer array with at least five elements.
  • Print the same element using a[i], *(a + i), and i[a].
  • Loop through the array and print every element using indexing.
  • Loop through the array again using a pointer.
  • Avoid any out-of-bounds access.
Take Quiz

Keep learning

Related questions

View more