What the code is supposed to do
The function printOddNumbers takes a number n and should print the odd numbers smaller than n, one per line. The call printOddNumbers(8) should print 1, 3, 5 and 7. The number 8 itself is even, and the loop stops before reaching it.
The code you start with compiles, but it prints nothing:
func printOddNumbers(n int) {
for i := 0; i < n; i++ {
if n % 2 == 1 {
fmt.Println(n)
}
}
}
// Do not change this code:
func mainFunction() {
printOddNumbers(8)
}
What goes wrong
The loop header is correct: i goes from 0 to n - 1, which is 0 to 7. The problem is that the two lines inside the loop never use i. They use n, the parameter.
The parameter n is 8, and it stays 8 for the entire run. Only i changes from pass to pass. So the test n % 2 == 1 asks the same question eight times, "is 8 odd?", and the answer is always no. The body never runs, which is why nothing is printed.
Had n been odd, say 9, the opposite would happen. The test would always be true, and the function would print the number 9 nine times, once per pass. This bug is easy to miss because the loop still looks reasonable.
Fixing it step by step
- Find the variable that changes. In this loop, it is
i. The parameternonly sets where the loop stops. - Test
iin the condition. Changen % 2 == 1toi % 2 == 1, so that each pass asks whether the current number is odd. - Print
i. Changefmt.Println(n)tofmt.Println(i), so that the odd number found is the one printed.
The fixed code in Go
func printOddNumbers(n int) {
for i := 0; i < n; i++ {
if i % 2 == 1 {
fmt.Println(i)
}
}
}
func mainFunction() {
printOddNumbers(8)
}
Tracing it with n = 8: 0 gives remainder 0 and is skipped, 1 gives remainder 1 and is printed, 2 is skipped, 3 is printed, and so on up to 7. The loop ends when i reaches 8, so the output is 1, 3, 5, 7.
A few details about Go:
- The compiler won't catch this. Both
nandiare used, and the types are right. The program is valid, just wrong, so only running it reveals the problem. - The bound is exclusive.
i < nstops atn - 1. Ifnwere 7, the last odd number printed would be 5, not 7. %and non-negative numbers. For the values 0 and above that this loop produces, a remainder of 1 means odd.
How to spot this kind of bug
When a loop prints nothing, or prints the same thing repeatedly, ask which variables the body actually reads. A loop variable that is declared in the header but never mentioned in the body is a warning sign, because the body then does the same work on every pass. Here i appears only in the header. In Go the compiler accepts this, since a variable used in a loop condition counts as used. Adding a temporary fmt.Println(i, n) inside the loop shows at once that i changes while n does not.
Common mistakes
- Fixing only one line. Changing the test to
i % 2 == 1but still printingnwould print 8 four times. - Changing the loop instead. The header was never the problem. Rewriting it to
i <= nadds an extra pass without fixing anything. - Starting from 1 and printing every number. Without the remainder test, even numbers would be printed too.
- Using
i / 2. Division gives a quotient. To find odd numbers, you need%.
Checking your fix
Run the corrected function and the output should be exactly four lines: 1, 3, 5 and 7. With n = 1 or n = 0, nothing is printed, because no odd number is smaller than 1.