What goes wrong
The characters of a string have indexes from 0 to Length - 1. Any index outside that range is invalid, and using one throws an IndexOutOfRangeException at run time. The compiler can't catch it, because the index is usually only known when the program runs.
string car = "ford";
Console.WriteLine(car[0]); // f
Console.WriteLine(car[3]); // d
Console.WriteLine(car[4]); // IndexOutOfRangeException
The string has 4 characters, so the valid indexes are 0, 1, 2 and 3. Index 4 is one position past the end. An index such as 30 fails the same way, and so does a negative one like car[-1].
The exception's message says that the index was outside the bounds of the array, even though a string is not an array. The program stops at that line unless the exception is caught, so no later statements run.
Why it is so common
Most out-of-range errors come from one idea: confusing a count with a position. Length is how many characters there are, and the last position is one less than that. Writing car[car.Length] is the classic off-by-one error.
Two other situations cause it often:
- Empty strings.
""has no valid index at all, so even""[0]throws. - Loops that run too far. A loop written as
i <= s.Lengthreaches an index that doesn't exist on its last pass. The correct condition isi < s.Length.
Tracing a loop bug
Here is a loop that looks right but goes one step too far:
string car = "ford";
for (int i = 0; i <= car.Length; i++) {
Console.WriteLine(car[i]);
}
It prints f, o, r and d, and then the loop tries i = 4. The condition 4 <= 4 is true, so the body runs with car[4] and throws. Changing <= to < stops the loop after index 3.
When you hit this exception, find the index expression on the failing line and work out its value for the string involved. Compare it to the range 0 to Length - 1. That usually shows the problem straight away.
Guarding against it
Check the index before you use it:
string car = "ford";
int i = 4;
if (i >= 0 && i < car.Length) {
Console.WriteLine(car[i]);
} else {
Console.WriteLine("Index " + i + " is out of range");
}
This prints Index 4 is out of range. For the last character, compute the index from the length and make sure the string is not empty first.
Catching the exception
You can also catch the exception with try and catch so the program continues:
string car = "ford";
try {
Console.WriteLine(car[4]);
} catch (IndexOutOfRangeException) {
Console.WriteLine("That index does not exist");
}
This prints That index does not exist. Catching is a safety net, though. For a plain index check, testing the index first is simpler and says more clearly what the code expects.
A related exception
Indexing with [] throws IndexOutOfRangeException, but Substring reports a bad request with a different type, ArgumentOutOfRangeException. Code written for other languages may expect different exception names, so match the one C# actually throws when you catch errors.
string car = "ford";
Console.WriteLine(car.Substring(2, 2)); // rd
Console.WriteLine(car.Substring(2, 5)); // ArgumentOutOfRangeException
The second call fails because only two characters remain after index 2, and the call asks for five. The idea is the same as with indexing: the request has to stay inside the string.
The exercise, step by step
The lesson starts with message = "I love pancakes" and a line that is meant to print the last character, s. Instead the program stops with an IndexOutOfRangeException.
- Count the characters. The string has 15 characters, so
message.Lengthis 15 and the valid indexes are 0 to 14. - Spot the bad index. The starter code indexes with
message.Length, which is 15, one past the end. - Subtract one. The last character is at
message.Length - 1, which is 14.
string message = "I love pancakes";
Console.WriteLine(message[message.Length - 1]);
The program now prints s.
Key takeaways
- Valid indexes are
0toLength - 1; anything else throwsIndexOutOfRangeException. s[s.Length]is always one too far.- An empty string has no valid index.
- Loops over a string should use
i < s.Length, not<=. - When an index might be invalid, check it before using it.