I need help in understanding the logic behind the zero-based numbering and the length property = -1.
Zero-based arrays have their roots in C and even assembler. With C, pointer math basically works like this:
Each element of an array occupies a certain number of bytes. A 32 bit integer is (obviously) 4 bytes;
The address of an array is occupied by the first element of the array with subsequent elements in equal-sized contiguous blocks after that.
To illustrate, assume int a is at 0xFF00, the addresses are:
a -> 0xFF00;
a -> 0xFF04;
a -> 0xFF08;
a -> 0xFF0C.
So, with zero based indices, the addres math is simple:
Address of element = Address of array + index * sizeof(type)
In fact the expressions in C are all equivalent:
With one-based arrays, the math is (ever so) slightly more complicated.
So the reasons are largely historical.
An array of
n elements has
0 is the first index of the array this means the last index of the array is
n-1 because there are
n indexes from
n-1 - so the last index in terms of
length - 1
For why zero-based numbering is common in programming see
For why zero-based numbering is right for programming see
I like to think of it like a measuring tape or ruler: 1 isn’t the far edge of the ruler, 0 is. You can’t use ‘1’ until you pass it. So, based on that, item 2 in the below ascii art is technically in the ‘1’ block.
item1 item2 item 3 |--------|--------|---------| 0 1 2 3
Remembering that you can’t use it until you pass it means that you can never use arr.length because that number hasn’t been passed. The last item is still in the previous block… so you need to
-1 to get there. There are 3 items in the ascii art, but item 3 is still in block 2.
Same analogy works for birthdays. A newborn baby isn’t 1 (unless you’re doing that crazy asian thing where they count from conception ), it’s 0 until it’s first birthday.
All of our standard measuring practices are actually zero-based. Most people aren’t forced to realize that though.