The valid indexes of a C style array are the numbers from 0 to one less than the number of elements.
Every access must be within those bounds.
Outside of those bounds is one of the most common sources of undefined behavior when working with arrays.
Valid indexes of an array with 4 elements would be 0, 1, 2, and 3.
Index 0 refers to the first element, and index 3 refers to the last.
Index 4 is out of the bounds of the array.
#include <iostream>
int main()
{
int data[4] = {10, 20, 30, 40};
std::cout << data[0] << '\n';
std::cout << data[3] << '\n';
// data[4] is already outside the array.
return 0;
}
An expression with an invalid array index references something that is not part of that array.
A C style array is not required to perform a bounds check at runtime in C++. As a result, a program with an invalid index might do any of the following: it might read the wrong information, it might crash and stop running, or it might just appear to work until later in the program.
There is not only risk in reading past the last element; there is also writing past the last element. An assignment with an invalid array index writes to some memory address that is outside of the array's boundaries.
This memory may belong to another array, to call stack information, or other data.
#include <iostream>
int main()
{
int values[3] = {1, 2, 3};
values[3] = 99;
std::cout << values[0] << ' ' << values[1] << ' ' << values[2] << '\n';
return 0;
}
The elements that belong to the array may seem fine after the invalid write, giving the false impression that no damage was done.
The overwritten memory may have belonged to other data that has not yet been used.
A common source of invalid index access is from loops which iterate over arrays. An array traverser that goes from index 0 to size with the condition i <= size in a loop will visit the index with the value size during the last iteration.
Writing index = size in the loop condition instead of index < size is one of the most common causes of off by one errors. The last element of the array can be accessed by simply writing size - 1 instead of the literal index number and using the array traverser will then keep a valid position within the array bounds at all times.
#include <iostream>
int main()
{
int numbers[5] = {5, 10, 15, 20, 25};
// Increment the value before the expression uses it
for (int i = 0; i <= 5; ++i)
{
std::cout << numbers[i] << '\n';
}
return 0;
}
The size of an array specifies the number of elements in it. It is not the highest index. Four elements have indexes from 0 to 3.
Index size - 1 must therefore be the last index accessible within the bounds of an array, and writing index = size in a loop condition is an index that references data beyond the end of the array.
Last element should be accessed as array[size - 1] to remain within the bounds.
#include <iostream>
int main()
{
const int size = 4;
double samples[size] = {1.1, 2.2, 3.3, 4.4};
// samples[size] is out of bounds.
std::cout << samples[size - 1] << '\n';
return 0;
}
Since the compiler does not check that arrays are properly addressed, the programmer must make sure they don't outstep the bounds of the array. Always start a loop from index 0 and write, so that the loop traverses only if the index is less than the size of the array.
The size should be written as a variable with a descriptive constant name in order to change the upper bound simply by changing the size when the array is declared at the beginning. The last array element will thus be array[size - 1].
for (int i = 0; i < exact_size; ++i)
{
// Access array[i] here.
}
Undefined behavior because of an invalid index is tricky to debug since it can make a program do anything at any time depending on a host of factors such as the compiler used or the compiler's optimization settings. Keeping your indexes in range between 0 and size - 1 will ensure that none of this undefined behavior occurs.
A C style array's bounds are constant once it has been decided what size it will be, and writing to or reading past it is a guaranteed way of getting into serious trouble.
0 comments
No comments yet. Be the first.