If we use an array index that is out of bounds, then the compiler will probably compile and even run. But, there is no guarantee to get the correct result. Result may unpredictable and it will start causing many problems that will be hard to find. Therefore, you must be careful while using array indexing.
Answer. Accessing an element that is outside the bounds of the array results in a runtime error in the form of ArrayIndexOutOfBoundsException.
The array index out of bounds error is a special case of the buffer overflow error. It occurs when the index used to address array items exceeds the allowed value. It's the area outside the array bounds which is being addressed, that's why this situation is considered a case of undefined behavior.
ArrayIndexOutOfBoundsException may occur if an array is accessed out of bounds. But there is no such functionality in C and undefined behaviour may occur if an array is accessed out of bounds.
Welcome to every C/C++ programmer's bestest friend: Undefined Behavior.
There is a lot that is not specified by the language standard, for a variety of reasons. This is one of them.
In general, whenever you encounter undefined behavior, anything might happen. The application may crash, it may freeze, it may eject your CD-ROM drive or make demons come out of your nose. It may format your harddrive or email all your porn to your grandmother.
It may even, if you are really unlucky, appear to work correctly.
The language simply says what should happen if you access the elements within the bounds of an array. It is left undefined what happens if you go out of bounds. It might seem to work today, on your compiler, but it is not legal C or C++, and there is no guarantee that it'll still work the next time you run the program. Or that it hasn't overwritten essential data even now, and you just haven't encountered the problems, that it is going to cause — yet.
As for why there is no bounds checking, there are a couple aspects to the answer:
std::vector
class template, which allows both. operator[]
is designed to be efficient. The language standard does not require that it performs bounds checking (although it does not forbid it either). A vector also has the at()
member function which is guaranteed to perform bounds-checking. So in C++, you get the best of both worlds if you use a vector. You get array-like performance without bounds-checking, and you get the ability to use bounds-checked access when you want it.Using g++, you can add the command line option: -fstack-protector-all
.
On your example it resulted in the following:
> g++ -o t -fstack-protector-all t.cc
> ./t
3
4
/bin/bash: line 1: 15450 Segmentation fault ./t
It doesn't really help you find or solve the problem, but at least the segfault will let you know that something is wrong.
g++ does not check for array bounds, and you may be overwriting something with 3,4 but nothing really important, if you try with higher numbers you'll get a crash.
You are just overwriting parts of the stack that are not used, you could continue till you reach the end of the allocated space for the stack and it'd crash eventually
EDIT: You have no way of dealing with that, maybe a static code analyzer could reveal those failures, but that's too simple, you may have similar(but more complex) failures undetected even for static analyzers
It's undefined behavior as far as I know. Run a larger program with that and it will crash somewhere along the way. Bounds checking is not a part of raw arrays (or even std::vector).
Use std::vector with std::vector::iterator
's instead so you don't have to worry about it.
Edit:
Just for fun, run this and see how long until you crash:
int main()
{
int arr[1];
for (int i = 0; i != 100000; i++)
{
arr[i] = i;
}
return 0; //will be lucky to ever reach this
}
Edit2:
Don't run that.
Edit3:
OK, here is a quick lesson on arrays and their relationships with pointers:
When you use array indexing, you are really using a pointer in disguise (called a "reference"), that is automatically dereferenced. This is why instead of *(array+1), array[1] automatically returns the value at that index.
When you have a pointer to an array, like this:
int arr[5];
int *ptr = arr;
Then the "array" in the second declaration is really decaying to a pointer to the first array. This is equivalent behavior to this:
int *ptr = &arr[0];
When you try to access beyond what you allocated, you are really just using a pointer to other memory (which C++ won't complain about). Taking my example program above, that is equivalent to this:
int main()
{
int arr[1];
int *ptr = arr;
for (int i = 0; i != 100000; i++, ptr++)
{
*ptr++ = i;
}
return 0; //will be lucky to ever reach this
}
The compiler won't complain because in programming, you often have to communicate with other programs, especially the operating system. This is done with pointers quite a bit.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With