Start learning free

LESSON 95 OF 338 · ARRAYS I

Exceeding Static Array Bounds in Go

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 length - 1. Any index which is not in this range is invalid.

When you try to access an item with an invalid index, Go doesn't throw an error, but simply returns a random value:

myArray := [3]int{50, 40, 30}

// Valid indices: 0, 1, 2
fmt.Println(myArray[0]) // Output: 50
fmt.Println(myArray[2]) // Output: 30

// Invalid indices: 3, 30, -1
fmt.Println(myArray[3])  // random value like 1261279744
fmt.Println(myArray[30]) // random value like 1276947770
fmt.Println(myArray[-1]) // random value like -2712947770

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

    GO · ARRAYS I

    Exceeding Static Array Bounds in Go, explained

    Valid and invalid indices

    An array of n elements has the indices 0 to n - 1. Any other index is outside the array's bounds. This is the most common mistake when working with arrays, and Go does not let it slip by: reading or writing outside the bounds is always an error. It never quietly returns some leftover value from memory.

    Go reports the error at one of two moments, depending on what the index is.

    A constant index: a compile error

    The length of an array is part of its type, so the compiler knows it. If the index is a constant too, the compiler can check it before the program runs and refuses to build:

    myArray := [3]int{50, 40, 30}
    
    fmt.Println(myArray[2])  // fine: 30
    fmt.Println(myArray[3])  // compile error
    fmt.Println(myArray[-1]) // compile error
    

    The messages are invalid argument: index 3 out of bounds [0:3] and invalid argument: index -1 (constant of type int) must not be negative. Because the build stops, no part of the program runs, not even the lines before the mistake.

    Go treats len of an array as a constant too. That is why the lesson's starting code fails to compile:

    ages := [4]int{14, 32, 50, 21}
    
    fmt.Println(ages[len(ages)])
    
    invalid argument: index 4 out of bounds [0:4]
    

    The value of len(ages) is 4, and the last valid index is 3. The compiler spotted this before anything ran.

    A variable index: a run-time panic

    When the index comes from a variable, the compiler cannot know its value, so the check happens while the program runs. An out-of-range index then triggers a panic, which stops the program with a message:

    ages := [4]int{14, 32, 50, 21}
    k := 4
    fmt.Println(ages[k])
    
    panic: runtime error: index out of range [4] with length 4
    

    The message names the bad index and the length, followed by a trace of where it happened. Read it first when you debug: it says exactly which index was wrong.

    The exercise

    The starting code tries to print the last element:

    ages := [4]int{14, 32, 50, 21}
    
    fmt.Println(ages[len(ages)])
    

    It must print 21. The mistake is the index. Counting starts at 0, so the four elements sit at 0, 1, 2 and 3, and len(ages) is one too large. Subtract 1:

    ages := [4]int{14, 32, 50, 21}
    
    fmt.Println(ages[len(ages)-1])
    
    21
    

    Writing ages[3] would print the same thing, but len(ages) - 1 keeps working if the array's size changes later, so it is the better habit.

    Staying inside the bounds

    A few habits keep your indices valid, and they cost almost nothing to follow:

    • Use len(array) - 1 for the last index instead of a hard-coded number.
    • In a counting loop, use i < len(array), not i <= len(array).
    • Prefer for i := range array, which only produces valid indices.
    • Check a computed index with an if before using it: if k >= 0 && k < len(ages).

    A guard in practice

    When an index comes from outside your code, test it before you use it. This loop tries three indices, and only the valid one reads the array:

    for _, k := range []int{2, 4, -1} {
    	if k >= 0 && k < len(ages) {
    		fmt.Println(k, ages[k])
    	} else {
    		fmt.Println(k, "out of range")
    	}
    }
    
    2 50
    4 out of range
    -1 out of range
    

    The condition checks both ends of the range, because a negative index is as invalid as one that is too large.

    Common mistakes

    • Treating the length as the last index. This is the off-by-one in the exercise.
    • Expecting a negative index to count from the end. Go has no such feature, and a constant negative index is a compile error.
    • Trusting a computed index. An index that comes from arithmetic, such as i + 1 at the last position of a loop, is the usual source of a run-time panic.
    • Writing past the end. Assigning to ages[4] breaks the same rule as reading it. An array never grows.
    • Expecting a garbage value. Go does not hand back unrelated memory for a bad index. You get either a compile error or a panic.

    Key takeaways

    • Valid indices are 0 to len(array) - 1.
    • A constant index outside the array is rejected by the compiler.
    • A variable index outside the array makes the program panic when it runs.
    Keep going with GoAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free