Start learning free

LESSON 133 OF 415 · LOOPS & CONDITIONALS

Print Odd Numbers in Swift: Fixing the Buggy Code

Practice Read the full explanation

Inside the code editor we've tried to write a function that takes a number n as argument and prints to the console the odd numbers smaller than n.

So when we called printOddNumbers(8), we expected our code to print:

1
3
5
7

but it seems like we made some mistakes because when we run our code, it prints nothing.


Assignment:

Your task is to fix our function such that it prints the odd numbers smaller than n.

STEP 1 OF 1
    Ctrl + Enter to check

    SWIFT · LOOPS & CONDITIONALS

    Buggy Code Print Odd Numbers in Swift, explained

    What the code is supposed to do

    The function printOddNumbers takes an integer n and prints the odd numbers below it, one per line. Calling printOddNumbers(8) should print 1, 3, 5 and 7. The starter code compiles and runs without errors, but it prints nothing at all:

    func printOddNumbers(_ n: Int) {
        for i in 0..<n {
            if n % 2 == 1 {
                print(n)
            }
        }
    }
    

    Your job is to find out why and fix the two lines inside the loop.

    What goes wrong

    The loop header is correct. 0..<n is a half-open range: it contains 0, 1, 2 and so on up to n - 1, and the variable i takes one of those values on each pass. For n = 8 the loop runs eight times, with i from 0 to 7.

    The trouble is that the body never looks at i. Both lines use the parameter n, which stays 8 for the whole call:

    • n % 2 == 1 asks whether 8 is odd. It is not, and it never will be during this call, so the condition is false on every pass.
    • Even if the condition were true, print(n) would print 8 each time, not the number the loop is currently at.

    The result is a loop that spins eight times and does nothing. The compiler gives a hint: it warns that the immutable value i was never used and suggests replacing it with _ or removing it. A loop variable that is never read is a strong sign that the body is working with the wrong variable.

    The same bug has a second face. Call printOddNumbers(5) with the starter code and n % 2 == 1 is true on every pass, so the function prints 5 five times. Which behaviour you see depends only on whether n is odd, which is another way to tell that the loop variable is being ignored.

    Fixing it step by step

    1. Leave the loop header alone. for i in 0..<n already visits every candidate from 0 to n - 1.
    2. Change the test to use i. The question for each pass is whether the current number is odd, so the condition becomes i % 2 == 1.
    3. Print i. The number to show is the one that passed the test, so print(n) becomes print(i).

    The fixed code in Swift

    func printOddNumbers(_ n: Int) {
        for i in 0..<n {
            if i % 2 == 1 {
                print(i)
            }
        }
    }
    
    
    func mainFunction() {
        printOddNumbers(8)
    }
    

    Calling printOddNumbers(8) prints:

    1
    3
    5
    7
    

    A few Swift details are worth knowing here:

    • Half-open versus closed ranges. 0..<n stops before n, while 0...n includes n. Swapping the operator would change the answer only when n itself is odd: printOddNumbers(7) would print 1, 3, 5 with 0..<7 and 1, 3, 5, 7 with 0...7. Keep the operator the code already has.
    • The remainder operator. % gives the remainder after division, so i % 2 is 0 for even numbers and 1 for odd ones. Because the loop starts at 0, every i is non-negative and comparing with 1 is safe. For negative numbers the remainder takes the sign of the dividend: -3 % 2 is -1, so a test written as x % 2 == 1 would miss negative odd numbers. x % 2 != 0 works for both signs.
    • Parameters are constants. Inside a Swift function, n can't be reassigned. That is one reason the fix uses the loop variable rather than changing n.
    • The label _. The function is declared with _ n: Int, so the call is printOddNumbers(8) without an argument label.

    Edge cases and common mistakes

    • Testing n instead of i. This is the bug in the lesson. Whenever a loop variable exists, check that the body actually reads it.
    • Testing i but printing n. The condition would pick the right passes, but every line would show the same number.
    • Zero and one. printOddNumbers(0) and printOddNumbers(1) print nothing: the first range is empty, and the second contains only 0, which is even.
    • Printing the even numbers instead. Comparing with 0, as in i % 2 == 0, would print 0, 2, 4 and 6.

    Testing

    • printOddNumbers(8) prints 1, 3, 5, 7.
    • printOddNumbers(7) prints 1, 3, 5.
    • printOddNumbers(2) prints 1.
    • printOddNumbers(1) prints nothing.
    Keep going with SwiftAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free