In C++ and C the iteration idiom almost always looks like:
for (elementIndex = first-element; elementIndex < indexAfterLastElement; elementIndex++) {
...
}
That is, writing the equivalent of the mathematical notation:
firstElementIndex <= elementIndex < indexAfterLastElement
Two advantages of that idiom:
The first one is that indexAfterLastElement - firstElementIndex equals the number of elements being scanned.
The second advantage (which is the most debatable, and personal) is that the initial boundary condition is trivial (it's the first element) and the end boundary condition is natural i.e. just look past the element you are looking at whether there is a next one. That's what Dijkstra is talking about when telling the example of the student who would not look past the end of the page.
I used the epithet natural because for most of the objects we interact with, the end is not part of the object, rather it is the transition in between the last element and nothingness.
Now that said (in too many words) if you compare 1-based arrays and 0-based arrays you have:
for (i = 0; i < N; i++) {
...
}
for (i = 1; i < N + 1; i++) {
...
}
Both would be acceptable. However 0 based arrays have the advantage of giving
i two meanings:
1. the index of the current element
2. the number of elements scanned so far.
At the end of the iteration,
i also conveniently contains the number of elements having been scanned. Which can be useful in algorithms where there is an extra condition which might let you leave the iteration early.
This to me is the most important part, zero-based indexing is more expressive.