Why Array Index Starts from 0: The Real Reason Behind the Scenes

Published: (January 17, 2026 at 01:03 AM EST)
3 min read
Source: Dev.to

Source: Dev.to

If you’ve ever written code, you’ve probably asked this question at least once:

“Why do arrays start from index 0 instead of 1?”

At first glance, starting from 1 feels more natural—humans count 1, 2, 3…—but almost every major programming language (C, C++, Java, Python, JavaScript, Go, Rust, etc.) uses zero‑based indexing. This is not a random decision. Below we break down the real reasons, from hardware memory to compiler design, and see why index 0 is actually the most efficient choice.

Memory layout and offsets

An array is a continuous block of memory.

arr = [10, 20, 30, 40]

Memory address:
1000 → 10
1004 → 20
1008 → 30
1012 → 40
  • Base address – the address of the first element (here 1000).
  • Element size – number of bytes per element (here 4 bytes).

The address of an element is computed as:

address = base_address + (index * element_size);
  • arr[0]1000 + (0 * 4) = 1000
  • arr[1]1000 + (1 * 4) = 1004
  • arr[2]1000 + (2 * 4) = 1008

Index 0 means no offset—the element resides exactly at the base address.
If arrays started at 1, the formula would become:

address = base_address + ((index - 1) * element_size);

The extra “‑1” adds a subtraction for every access, slowing execution and complicating compiler logic.

Pointer arithmetic in C

Zero‑based indexing fits naturally with pointer arithmetic, which is why C popularized it.

arr[i]  ==  *(arr + i);
  • arr is a pointer to the first element.
  • i is the offset (how many elements forward to move).

Thus:

arr[0] = *(arr + 0);   // first element
arr[1] = *(arr + 1);   // second element

Languages that inherited C’s semantics (Java, JavaScript, Python, Go, Rust, …) kept zero‑based indexing for consistency and performance.

Clean loop constructs

Zero‑based indexing makes loops concise and eliminates off‑by‑one errors at the machine level.

for (let i = 0; i < arr.length; i++) {
    console.log(arr[i]);
}
  • Start at 0.
  • Stop before length.

Because length is the count of elements, not the last index, the loop condition i < arr.length is naturally correct.

If indexing started at 1, loop logic would require an extra subtraction or an adjusted termination condition, adding unnecessary comparisons.

Half‑open intervals and slicing

Many languages adopt the half‑open interval convention [start, end) for slices:

arr = [10, 20, 30, 40, 50]
sub = arr[0:3]   # → [10, 20, 30]
  • Start index = offset from the base.
  • End index = count of elements to include.

This yields:

  • No overlap between consecutive slices.
  • No ambiguity about the length of the slice (end - start).

Half‑open intervals are mathematically clean and enable efficient implementations of slicing, range loops, and iterator arithmetic.

Mathematical and theoretical foundations

In mathematics and theoretical computer science, counting often starts at 0:

  • Sequences are indexed from 0 (the first element has offset 0).
  • Graph traversal, finite‑state machines, and automata theory use zero‑based numbering to represent distances from a start state.

Treating an index as a distance rather than a human‑oriented ordinal aligns with these models and simplifies proofs and algorithm design.

Performance impact at scale

A single extra subtraction (index - 1) may seem negligible, but consider:

  • Millions of array accesses inside tight loops (e.g., graphics engines, scientific simulations).
  • Cache friendliness: zero‑based calculations map directly to address arithmetic, reducing instruction count.
  • Compiler optimizations: simpler address calculations enable more efficient generated code.

At large scale, eliminating even a tiny per‑access overhead can translate into measurable performance gains.

Languages with non‑zero‑based indexing

Some languages choose human‑friendly indexing:

  • MATLAB – 1‑based arrays.
  • Lua – 1‑based by default (but can be changed).
  • Fortran – historically 1‑based.

Even in these languages, compilers ultimately translate array accesses to zero‑based memory offsets internally, incurring a translation cost.

Bottom line

Array indexing starts at 0 because:

  • Memory works with offsets from a base address.
  • Zero‑based indexing aligns perfectly with pointer arithmetic.
  • It yields simpler, faster loops and half‑open interval semantics.
  • It matches the mathematical notion of distance from the start of a sequence.

Understanding the hardware‑level reasoning makes index 0 feel inevitable rather than arbitrary.

Back to Blog

Related posts

Read more »

🚂 Arrays Explained Like You're 5

The Train Imagine a train with numbered compartments: 🚂 Car 0 Car 1 Car 2 Car 3 Car 4 Each car has a number starting from 0! and can hold one thing. Arrays ar...