the off-by-one and fencepost error
Here is a riddle that catches almost everyone: to build a straight fence 10 metres long with a post every metre, how many posts do you need? The tempting answer is 10. The right answer is 11 — one for each end plus the nine in between. Miscounting by exactly one, because you confused the gaps with the posts, is so common it has a name: the fencepost error, and its programming cousin is the off-by-one error. It is the most ordinary, most frequent bug in all of programming, and in C it routinely turns into undefined behavior.
The error is using a count that is one too high or one too low: looping one time too many, allocating one byte too few, indexing one past the end. C makes it easy to commit because arrays are zero-indexed: an array of n elements has indices 0 to n-1, so the last valid index is n-1, NOT n. The two classic forms: a loop written for (i = 0; i <= n; i++) runs n+1 times and touches a[n], which is out of bounds; and forgetting that a C string needs ONE extra byte for its terminating null, so a 5-character string needs a 6-byte buffer, and allocating exactly 5 leaves no room for the '\0'. Off-by-one is also a leading cause of the dangerous case: writing one element past a buffer is a buffer overflow, and that single stray byte can corrupt a neighbour or smash a return address.
Why this matters: off-by-one errors are easy to make and easy to overlook because the program usually 'almost' works — it handles the middle correctly and only stumbles at the very first or very last element. Two habits tame them. First, prefer half-open ranges: write loops as 0 <= i < n (use < not <=), which is exactly why a[0..n-1] and 'for (i = 0; i < n; i++)' pair so cleanly. Second, when sizing buffers for strings, always add one for the null terminator and say so in the code (malloc(len + 1)). Drawing the boundary cases on paper — what happens at i = 0 and at i = n - 1 — catches most of them before they ship.
/* off-by-one loop: touches a[n], out of bounds */ for (int i = 0; i <= n; i++) sum += a[i]; /* should be i < n */ /* off-by-one allocation: no room for the '\0' */ char *s = malloc(strlen(src)); /* needs strlen(src) + 1 */ strcpy(s, src); /* overflows by one byte */ char *ok = malloc(strlen(src) + 1); /* +1 for the terminator */
Two everyday off-by-ones: <= instead of < walks past the array; forgetting the +1 for the null terminator overflows the buffer by one byte.
For an array of n elements the valid indices are 0..n-1, so the last index is n-1, not n. Prefer the half-open range 'i < n', and always allocate strlen + 1 bytes for a C string to hold its null terminator.