Start learning free

LESSON 101 OF 415 · ARRAYS I

Exceeding Static Array Bounds in Swift

Lesson Read the full explanation

When accessing array data with indices, the most common problem we can run into is exceeding the array's bounds.

Remember, the items of an array are indexed from 0 to count - 1. Any index which is not in this range is invalid.

When you try to access an item with an invalid index, Swift stops the program with a fatal error (it is not an exception you can catch):

var ourArray = [50, 40, 30]

// Valid indices: 0, 1, 2
print(ourArray[0]) // Output: 50
print(ourArray[2]) // Output: 30

// Invalid indices: 3, 30, -1
print(ourArray[3]) // Fatal error: Index out of range
print(ourArray[30]) // Fatal error: Index out of range
print(ourArray[-1]) // Fatal error: Index out of range

As programmers, we always want to make sure that we don't exceed one array's bounds in our programs.


Assignment
Follow the Coding Tutorial and let's play with some arrays.


Hint
Look at the examples above if you get stuck.


STEP 1 OF 1
    Ctrl + Enter to check

    SWIFT · ARRAYS I

    Exceeding Static Array Bounds in Swift, explained

    Valid and invalid indexes

    The items of an array are numbered from 0 to count - 1. Those are the array's bounds. Any other index is invalid, and using one is the most common mistake when working with arrays.

    let ourArray = [50, 40, 30]
    
    // Valid indexes: 0, 1, 2
    print(ourArray[0])  // 50
    print(ourArray[2])  // 30
    

    Indexes 3, 30 and -1 are all invalid for this array: 3 and 30 are past the end, and -1 is before the start. Swift does not wrap around or count from the end the way some languages do with negative numbers.

    What happens

    Reading or writing an invalid index stops the program immediately with a fatal error, usually reported as "Index out of range". It is not an exception you can catch with do and catch. Swift deliberately halts, because continuing with a wrong index could read or overwrite unrelated memory. Anything the program would have printed after that line never runs.

    Because the crash happens at run time, the compiler can't warn you in general. It doesn't know what a variable will hold:

    let ages = [14, 32, 50, 21]
    let position = ages.count
    print(ages[position])  // crashes: valid indexes are 0 to 3
    

    The exercise: fix the crash

    The starter code is meant to print the last age, 21:

    let ages = [14, 32, 50, 21]
    
    print(ages[ages.count])
    

    It crashes. Here is why, step by step.

    1. Find the count. ages.count is 4, because the array has four elements.
    2. Find the valid indexes. With four elements they are 0, 1, 2 and 3.
    3. Compare. The code reads index 4, one past the last element. That is outside the bounds.
    4. Fix the index. The last element is at count - 1, so subtract 1.
    let ages = [14, 32, 50, 21]
    
    print(ages[ages.count - 1])
    

    The program now prints 21.

    Staying inside the bounds

    When the index comes from a variable, test it before using it:

    let index = 4
    if index >= 0 && index < ages.count {
        print(ages[index])
    } else {
        print("out of range")  // this branch runs
    }
    

    ages.indices.contains(index) does the same check in one expression. For the first or last element, the optional properties first and last are safe: they give nil for an empty array instead of crashing. When you walk through all elements, use for i in 0..<ages.count, whose upper bound excludes the count, or for age in ages, which needs no index.

    Reading a crash report

    A crash like this is easy to fix once you know where to look. The failing line is the one that contains a subscript, so start with the number between the brackets and work out its value. If it comes from a variable or a calculation, evaluate it by hand with the array's real size. Then compare the result with the range 0 to count - 1. In most cases the index is off by one, or the array is shorter than the code assumed, for example because it is empty or because items were removed earlier.

    Common mistakes

    • Using count as the last index. It is one too many. The last index is count - 1.
    • Looping up to the count inclusive. 0...ages.count includes the invalid index 4. Use 0..<ages.count.
    • Using -1 for "the last item". Swift has no negative indexing.
    • Reading from an empty array. There, count - 1 is -1, which is invalid, and so is index 0.
    • Writing past the end. Assigning to ages[4] crashes too. It doesn't extend the array.

    Key takeaways

    • Valid indexes run from 0 to count - 1.
    • An invalid index crashes the program at run time.
    • The last element is array[array.count - 1].
    • Check an index that comes from a variable before using it.
    Keep going with SwiftAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free