Though it is a convention, it has demonstrable, objective benefits.
The use of 0 as the basis means that, in mathematical language, the indexing is homogeneous and that conversion between different units is a linear map.
Imagine if we have tape measure that measures both meters and centimeters. Imagine that the first tick on the tape measure, representing no displacement, is simultaneously labeled "1 cm" and "1 m" instead of 0.
Now, we no longer have a linear map to convert between cm and m. What we have is an affine map, like m = 1 + (cm - 1)/100.
An affine map is a strictly inferior alternative when we have the freedom to establish a linear map.
Homogeneous/linear is the superior default. One-based can be used in the special cases where it is nicer.
Here is one example: binary heaps. When we store a binary tree structure into a heap array, 1 based indexing makes the calculations nicer for navigating from parent to children or vice versa:
[1]
[2] [3]
[4][5] [6][7]
The children of every node [n] are [2n] and [2n + 1]. The parent of every node [n] is [n / 2] (floor-truncating division).
Under 0 based, it's not as nice:
[0]
[1] [2]
[3][4] [5][6]
The children are now [2n+1] and [2n+2]. One extra addition is required in the case of the left child. Finding the parent requires a subtraction: [(n-1)/2].
Another way to see the advantage of 1 based here is that every row of the tree starts with a power of : [1] [2] [4] ...
Because we are dealing with exponentiation, avoiding 0 helps: 0 is not a power of two, so to "boostrap" the exponentiation, we have to displace it.
Note that even though it is nice for a binary heap to use 1 based indexing, we still want to store that in an zero-based array, and just sacrifice the storage for the zero element.
If we use a zero based array, then the nice heap arithmetic we wrote in the source code will look nice in the object code, due to the map from the source code array to the object code array being a linear map, rather than an affine map.
It is almost always better to simulate a 1 based array by sacrificing a storage element, than to have the compiler uglify the beautiful indexing calculations for the sake of which we switched to 1 based in the first place.
In summary:
1. we should choose the representation which offers the most succinct indexing calculations for the given situation, and not for some emotional reasons like "children learn to count from 1 and non-programmers understand that best".
2. arrays should be zero-based to preserve the succinctness of the calculation through to the object code (linear map from source to object, not affine).
That's just another convention, though…