AP Computer Science A study materials
AP Computer Science A study resources

Off-By-One in a While-Loop Sentinel

AP Computer Science A · Put your knowledge to work in context.

All case studies

Off-By-One in a While-Loop Sentinel

A program reads daily temperatures from a scanner until it sees the sentinel value -999. The student writes:

int count = 0;
int sum = 0;
int t = in.nextInt();
while (t != -999) {
    sum += t;
    count++;
    t = in.nextInt();
}
System.out.println(sum / count);

The input is 70 72 68 -999. The program prints 70, which is correct. But when the input is just -999, the program crashes. Separately, a reviewer notes that a legitimate temperature of -999 could never be recorded, and that the loop reads one extra value if the file ends without a sentinel.

1. Explain why the all-sentinel input `-999` crashes, and identify the two design weaknesses the reviewer flagged.

Read the worked answer

With input -999, the priming read sets t = -999, the loop body never runs, so count stays 0. The final line computes sum / count = 0 / 0, which throws ArithmeticException. The loop logic is correct; the post-loop code assumes at least one data value.

Reviewer's two weaknesses:

  1. Sentinel collision. -999 is a plausible (if extreme) temperature, so using it as a sentinel makes that value unrecordable. A better design uses a value outside the valid domain, or a count-prefixed input, or hasNextInt().
  2. Unchecked end-of-input. in.nextInt() throws NoSuchElementException if the file ends without -999. The loop assumes a well-formed stream. A robust version checks in.hasNextInt() in the loop condition.

2. Rewrite the loop so it handles empty input gracefully and does not crash at end-of-file, keeping the sentinel check. State what the program should print for empty input and why.

Read the worked answer
int count = 0;
int sum = 0;
while (in.hasNextInt()) {
    int t = in.nextInt();
    if (t == -999) {
        break;
    }
    sum += t;
    count++;
}
if (count == 0) {
    System.out.println("no data");
} else {
    System.out.println(sum / count);
}

hasNextInt() guards both end-of-file and the priming read, so no NoSuchElementException. The break on the sentinel exits cleanly. For empty input, count == 0, so printing "no data" is correct - there is no meaningful average of zero values, and dividing would throw. The judgment call is that an average of an empty set is undefined, not zero; the program should say so rather than fabricate a value.