In everyday life, if we have N objects and want to identify them by numbers, we assign the numbers
1,2,3,. .., N to them. Another way to look at this is to say that the set of numbers forms a closed
interval which we can write as either 1 ≤ i ≤ N or [1, N].
Programmers are different. Given N objects, they number them 0,1,2,. .., N−1. This set of numbers
forms a semi-closed (or semi-open interval which we can write as either 0 ≤ i < N or [0, N). The
advantages of semi-closed intervals include:
• They reduce the risk of “off-by-one” or “fencepost” errors.
To see why off-by-one errors are called “fencepost errors”, consider the length of a fence with
N posts spaced 10 feet apart. The length of the fence is 10(N − 1)
• The closed interval [M, N] has N −M +1 elements; the semi-closed interval [M, N) has N −M
elements, which is easier to remember and calculate.
• Semi-closed intervals are easier to join together. Compare
[A, B), [B, C), [C, D),.. .
to
[A, B − 1], [B,C − 1], [C, D − 1],.. .
• The index of the first element of an array A in C++ is 0. The address of the I’th element of the
array is &A + sI where &A is the address of the array and s is the size of one element.
Typical C++ loops do not have the form
for (int i = M; i <= N; ++i) ....
but, instead, have the form
for (int i = M; i < N; ++i) ....
Note that, in the first case, N is the last element processed but, in the second case, N is the first element not processed. In fact, we will see later that there are good reasons for writing the termination
condition as != rather than <=:
for (int i = M; i != N; ++i) ....