If we initialize array with 4 elements, for example:
int array[4];
Can we assign values like this because it is also taking 4 values:
for(int i=5;i<9;i++){
cin>>array[i];
}
Out-of-bounds access on an array has undefined behaviour, which is another way of saying "unintended consequences":
int a[4];
int b[4];
for(int i=5;i<9;i++){
a[i] = i;
}
In a debugger watch what it's doing and in particular watch what happens to b.
This may or may not crash, but it's still broken code. C++ will not always alert you to such situations, it's your responsibility as a developer to be aware of what's allowed and not allowed when accessing certain structures.
Accessing an array out of bounds doesn't always cause a crash, but it is always problematic. Try with i = 999999 or i = -9 and see what happens.
The problem with undefined behaviour is that it may appear to be working but these unintended consequences eventually catch up with you. This makes debugging your code very difficult as this out-of-bounds write may stomp a variable that you need somewhere else minutes or hours after the initial mistake, and then your program crashes. Those sorts of bugs are the most infuriating to fix since the time between the cause and effect is extremely long.
It's the same as how throwing lit matches in the garbage may not cause a fire every time but when it does cause a fire you may not notice until it's too late. In C++ you must be extremely vigilant about not introducing undefined behaviour into your code.
You are mixing up two constructs - the logic used to iterate in a loop and the indexing of an array.
You may use
for(int i=5;i<9;i++){
...
}
to run the loop four times. However, you many not use those values of i to access the array. The array index has to be offset appropriately so it is valid.
for(int i=5;i<9;i++){
int index = i - 5;
std::cin >> array[index];
}
No, you get an array with 4 slots. Those slots are
array[0]
array[1]
array[2]
array[3]
So your code is incorrect. It might seem to work, but its still wrong due to whats called Undefined Behavior, next week it might fail
Note. You are better off using std::vector in c++
can we allocate value like this because it is also taking 4 values:
for(int i=5;i<9;i++){
cin>>array[i];
No, we can't. Since the size of the array is 4, the only indices that can be accessed are 0,1,2 and 3. Accessing any other index will have undefined behaviour.
try to run it in any online compiler it is working.
The behaviour is undefined. Possible behaviours include, none of which are guaranteed:
- working
- not working
- random output
- non-random output
- the expected output
- unexpected output
- no output
- any output
- crashing at random
- crashing always
- not crashing
- corruption of data
- different behaviour, when executed on another system
- , when compiled with another compiler
- , on tuesday
- , only when you are not looking
- same behaviour in all of the above cases
- anything else within the power of the computer (hopefully limited by the OS)
Related
Imagine the following definition.
struct X {
double a[8] {0.0};
double b[8] {0.0};
}
int main() {
X x;
x.a[10] = 1.0;
}
Is the behavior of the program undefined when I access x.a[10]?
Yes, it is undefined behavior, but not only because the compiler may alter the memory layout of X.
It is undefined behavior because the standard says so. As a result the compiler can do whatever with this code: the compiler can drop the assignment completely, can assign 1.0 to all the 16 elements, can change what previous code is doing, can crash the program, format your hard drive, etc.
A more realistic, classical example: the following function
const int table[4] = {2, 4, 6, 8};
bool exists_in_table(int v)
{
for (int i = 0; i <= 4; i++) {
if (table[i] == v) return true;
}
return false;
}
always return true, at least in modern gcc with -O3 (https://godbolt.org/z/f9cbWMYzM)
Yes. It's undefined behavior. Because the compiler could insert some padding between a and b. Il could also insert some padding after b.
The only thing you can be sure of is that no padding will be put before a.
An interesting and very detailed description is provided in The Lost Art of Structure Packing.
EDIT: Petr answer is more precise than mine: "It is undefined behavior because the standard says so." Anyway, sometimes you feel like "Well the standard says so, but it will always work in practice". So it may be useful to know what could happen in real case scenarios. It's unlikely (but possible) that an out of bound access will format your hard drive, and it's much more likely that two structure elements will not be contiguous in memory.
Your false premise is that out of bounds access would be defined, then of course it is ... not undefined. But it is not. You cannot know what data is at the accessed adress. Already the notion of some data being accessed at some adress is not right for the expression x.a[10].
You assume that the two arrays are stored in adjacent memory directly next to each other and that pointer arithmetics works also beyond the bounds of an array. The first is not true in general and the second is false always.
Pointer arithmetics is only defined within the bounds of an array.
Your code has undefined behavior.
Note that your code is not instructions for your CPU. Your code is an abstract description of what the program should do. And x.a[10] simply has no meaning in the language. It is not defined. The compiler is not mandated to translate it to anything useful.
It is according to the "undefined behavior sanitizer" built into g++/clang++
runtime error: index 10 out of bounds for type 'double [8]'
i.e. the out of bounds access you're already worried about, is indeed UB. It's very very risky doing assumptions on memory layout and usually (even when you know what you're doing) the resulting code is not portable.
Demo
Notice in the demo, invocation of the checker happened with -fsanitize=undefined. We have great tools, let's use them.
Also notice that if you enable the memory checker, i.e. -fsanitize=address, no warning is emitted. That is to say, "just because it doesn't cause runtime memory problems it doesn't mean it's not UB".
I use Clion(version 2018.02) to run the code.
Here is the code:
int a[10]={0};
cout<<a[-1]<<endl;
cout<<a[10]<<endl;
After several testing, I found that every time a[-1]=0; However, the value of a[10] is always changing.
I wonder why the phenomenon happens on a[10] is not found on a[-1]. In other words, I guess that a[-1] should be changing as well.
#
Actually I know those things above are undefined behaviors.
However, in my mind, undefined behaviors always mean that they are randomized. What I'm doing is just creating bugs, and then see why a[-1] is always a specific number. So that I can know how it works inside the memory stream.
THANKS A LOT!!
It depends on the environment you are using. For example in vs13 I'm getting same garbage value for both a[-1] and a[10] in debug mode, but in release mode I'm getting garbage value for a[-1] and 0 for a[10].
One thing that you can be sure about, in any case in these scenarios you will have undefined behavior and value should always be determine as garbage.
So I was working in c++ 11 and this occurred to me:
char s[100];
strcpy(s, "Andrei");
int n=strlen(Andrei); // (it would be 6)
I do this:
s[n]=' ';
s[n+9]='\0';
What happens with s[n+1], ... s[n+8]?
If I go
cout <<s;
The array will be displayed as normal.
But if I specify
cout <<s[n+2]
it will print odd characters
The array elements s[n+1] ... s[n+8] are uninitialized. They are said to have indeterminate value. Trying to output an indeterminate value causes undefined behaviour which means anything can happen.
So, you have a buffer of 100 chars. Due the fact there is no strict initialization policy in C++, you got a buffer of BIG SOMETHING. Content of that "big something" would differ between each app launch, may vary on different build modes (debug/release) etc. Indeed, querying that "something" is like trying to listen a radio on a random wave and hear a noise sequence in return (it could be different each time you do this).
Running your strcpy would initialize just first N chars, the rest of the buffer is still "something".
In the code below, I am trying to store the value of array at index 0 in the temp variable. In this line of code: a[i-1]=a[i]-a[i-1]; when i=0, a[i-1] becomes a[-1].
Why is compiler not giving any error?
Why does the value of temp variable is affected and becomes zero after the first iteration, though it is assigned a value only when i=0 and temp is not used anywhere else?
For example, when I gave input as:
3 1 2 3
Output:
i:0
a[0]: 1
TEMP: 1
TEMP: 0
TEMP: 0
TEMP: 0
What's actually happening? Please explain with reference to the working of compiler. I know that if I put a condition if(i!=0) a[i-1]=a[i]-a[i-1]; the code will work normally. But I want to know why is this happening with the given scenario.
#include<bits/stdc++.h>
using namespace std;
int main()
{
int a[10],i,n,temp;
cin>>n;
for(i=0;i<n;i++){
cin>>a[i];
if(i==0){
temp=a[i];
cout<<"i: "<<i<<endl;
cout<<"a[0]: "<<a[i]<<endl;
}
cout<<"TEMP: "<<temp<<endl;
a[i-1]=a[i]-a[i-1];
}
cout<<endl<<"TEMP: "<<temp;
}
Why is compiler not giving any error?
The compiler is not required to give any error. Accessing array out of bounds has undefined behaviour. It might seem obvious that the array is going to be accessed out of bounds at run time (then again, perhaps not so obvious since the author of the program didn't catch it before running the program), but it would be prohibitively expensive for the compiler to check execution paths in search for bugs in general.
Why does the value of temp variable is affected and becomes zero after the first iteration, though it is assigned a value only when i=0 and temp is not used anywhere else?
Because the behaviour of the program is undefined.
It is usually pointless to analyze why program behaves in some way, when it is allowed to behave in any possible way. However, this case it seems that most likely: When you write out of bounds, you overwrite some memory that isn't part of the array. Other variables may be located in the memory that isn't part of the array. Therefore overwriting some memory that isn't part of the array may corrupt the value of some other variable. That is what you observed.
Why is compiler not giving any error?
As #user2079303 already mentioned, such error is too difficult for compiler to find. There're separate tools for finding such more complicated errors - static and dynamic code analyzers. For example, if you use default static code analyzer from VS 2015, it gives the following warnings:
Severity Code Description
Warning C4701 potentially uninitialized local variable 'temp' used
Warning C6385 Reading invalid data from 'a': the readable size is '40' bytes, but '-4' bytes may be read.
Warning C6386 Buffer overrun while writing to 'a': the writable size is '40' bytes, but '-4' bytes might be written.
Warning C6001 Using uninitialized memory 'temp'.
If you want extra safety for your projects, consider enabling all (or almost all) available warnings and run code analysis regularly.
This question already has answers here:
Accessing an array out of bounds gives no error, why?
(18 answers)
Closed 9 years ago.
Why does this work without any errors?
int array[2];
array[5] = 21;
cout << array[5];
It printed out 21 just fine. But check this out! I changed 5 to 46 and it still worked. But when I put 47, it didn't print anything. And showed no errors anywhere. What's up with that!?!?
Because it's simply undefined behaviour (there is no checks for bounds of arrays in C++). Anything can happen.
Simply array[5] is equivalent to *(&array[0] + 5), you are trying to write/read to memory, that you are not allocate.
In the C and C++ language there are very few runtime errors.
When you make a mistake what happens instead is that you get "undefined behavior" and that means that anything may happen. You can get a crash (i.e. the OS will stop the process because it's doing something nasty) or you can just corrupt memory in your program and things seems to work anyway until someone needs to use that memory. Unfortunately the second case is by far the most common so when a program writes outside an array normally the program crashes only one million instructions executed later, in a perfectly innocent and correct part.
The main philosophical assumption of C and C++ is that a programmer never makes mistakes like accessing an array with an out-of-bounds index, deallocating twice the same pointer, generating a signed integer overflow during a computation, dereferencing a null pointer and so on.
This is also the reason for which trying to learn C/C++ just using a compiler and experimenting by writing code is a terrible idea because you will not be notified of this pretty common kind of error.
The array has 2 elements, but you are assigning array[5] = 21; which means 21 is in memory outside the array. Depends on your system and environment array[46] is a valid memory to hold a number but array[47] isn't.
You should do this
int array[47];
array[47] = 21;
cout << array[47];