What the code is supposed to do
The function printOddNumbers takes an Int named n and prints the odd numbers below it, one per line. Called with 8, it should print 1, 3, 5 and 7. The code you start with prints nothing at all:
fun printOddNumbers(n: Int) {
for (i in 0 until n) {
if (n % 2 == 1) {
println(n)
}
}
}
Notice that the loop covers 0 until n, so it stops at n - 1. The number n itself is never printed, which is why the expected output for 8 ends at 7. For printOddNumbers(9) the last line is also 7, not 9.
What goes wrong
The loop is fine: it makes i take the values 0, 1, 2, ..., n - 1. The mistake is in the two lines inside it, which both use n instead of i.
- The test uses
n. The parameter never changes while the function runs, son % 2 == 1has the same answer on every pass. Forn = 8the remainder is0, the test is always false, and nothing is printed. - The print uses
n. Even if the test passed, the line would printnagain and again instead of the current number.
Because the test only depends on n, the function behaves in one of two ways. For an even n it prints nothing. For an odd n it prints n itself, n times. With n = 3 the output is 3 three times:
3
3
3
Neither behaviour has anything to do with the odd numbers below n.
Fixing it step by step
- Find the variable that changes. Each pass of the loop gives
ia new value. The parameternstays the same, so onlyican tell one pass from another. - Test
iin the condition. Changen % 2 == 1toi % 2 == 1. The remainder after dividing by 2 is1for odd numbers and0for even ones. - Print
i. Changeprintln(n)toprintln(i)so that the number that passed the test is the one printed. - Leave the loop and the rest alone. The range, the braces and
mainFunctionare already correct.
The fixed code in Kotlin
fun printOddNumbers(n: Int) {
for (i in 0 until n) {
if (i % 2 == 1) {
println(i)
}
}
}
fun mainFunction() {
printOddNumbers(8)
}
Some Kotlin details behind these lines:
untilexcludes its end.0 until nruns from0ton - 1. The inclusive form is0..n, which would includenas well. With0..nandn = 9the function would also print9.- The loop variable is a
val. Infor (i in 0 until n),iis a fresh read-only value on every pass. You never writei++; the loop moves on by itself. %is the remainder operator. For non-negative numbers,i % 2is0wheniis even and1when it is odd. Hereiis never negative, so== 1is a safe test.- Negative numbers behave differently. In Kotlin the remainder takes the sign of the left operand, so
-3 % 2is-1, not1. If you ever need to test negative values, compare with!= 0instead of== 1. - Parameter names matter. Parameters are read-only values that stay the same during a call. When a loop variable and a parameter both hold numbers, it's easy to reach for the wrong name, and the compiler accepts either.
Edge cases and common mistakes
n = 0orn = 1. The loop covers0only, or nothing at all, and neither is odd, so the function prints nothing. That is the correct output.n = 2. The loop covers0and1, so the output is a single line,1.- Odd
n.printOddNumbers(9)prints1,3,5,7. The number9is odd but not below9, so it isn't printed. - Fixing only one line. Changing the test but not the print prints the wrong number: for
n = 8it prints8four times, once for each oddi. Changing the print but not the test still prints nothing for an evenn. - Testing for the wrong remainder.
i % 2 == 0selects even numbers, so it would print0, 2, 4, 6.
When a loop prints nothing, or the same value repeatedly, check whether the code inside it uses the loop variable. Code that never mentions it can't react to the loop.