The array index in C starts with 0 because in C the name of an array is a pointer, which is a reference to a memory location. Therefore, an expression *(arr + n) or arr[n] locates an element n-locations away from the starting location because the index is used as an offset. Likewise, the first element of the array is exactly contained by the memory location that array refers (0 elements away), so it should be denoted as *(arr + 0) or *(arr) or arr.
C programming language has been designed this way, so indexing from 0 is inherent to the language.
However, some languages give user a choice to start index from zero or any other positive integer. For an example, in Fortran, when an array is declared with integer a(10) (an array of 10 integer elements), the index starts from 1 and ends at 10. However, this behavior can be overridden using a statement like, integer a(0:9), declaring an array with indices from 0 to 9.
从数组存储的内存模型上来看，数组名称对应的是执行改数组在内存空间的其实地址，“下标”最确切的定义应该是“偏移（offset）”。前面也讲到，如果用 a 来表示数组的首地址，a 就是偏移为 0 的位置，也就是首地址，a[k] 就表示偏移 k 个 type_size 的位置，所以计算 a[k] 的内存地址只需要用这个公式：
a[k]_address = base_address + k * type_size
a[k]_address = base_address + (k-1)*type_size