This is a small snippet of code I was writing to test my knowledge of pointer :
int *grades;
*(grades+0) = 100;
*(grades+1) = 87;
*(grades+2) = 99;
*(grades+3) = 92;
cout<<*(grades+0)<<endl;
cout<<*(grades+1)<<endl;
cout<<*(grades+2)<<endl;
cout<<*(grades+3)<<endl;
I know the flaw in assigning pointers like this. However the above snippet of code correctly printed out the value of each of the grades. The issue is if I use a for loop to automate the display of the content of the pointers.
int *grades;
*(grades+0) = 100;
*(grades+1) = 87;
*(grades+2) = 99;
*(grades+3) = 92;
for(int i=0;i<4;++i)cout<<*(grades+i)<<endl;
Why does addition of a for loop causing segmentation fault. I know the reason of the segmentation fault, but isn't both snippets of code basically the same? I was using https://www.onlinegdb.com/ for writing the code.
Both scenarios (with or without the for loop) suffer from the same undefined behavior, and the nature of UB is that anything can happen. That is why your two snippets that are "basically the same", differ in behavior.
You code exhibits undefined behavior. grades points to invalid memory as it's uninitialized. Attempting to read or write through the pointer results in UB. It might look like it works but that's just one possible side effect of UB.
If you need a dynamic array use std::vector<int>, otherwise stick to std::array<int, 5>.
To make your current snippet work:
std::array<int, 4> a;
int* grades = a.data();
*(grades+0) = 100;
*(grades+1) = 87;
*(grades+2) = 99;
*(grades+3) = 92;
Your dynamic array is unitialized. So now it is pointed to a random address.
Try to do this:
int* grades = new int[4];
// do things
delete [] grades;
So, OS will assign some space for your 4 integers and not a random place where maybe there's another important value in it.
Related
I am running the following code where I declare a dynamic 2D array, and then go on to assign values at column indexes higher than the number columns actually allocated for the dynamic array. However, when I do this the code runs perfectly and I don't get an error, which I believe I should get.
void main(){
unsigned char **bitarray = NULL;
bitarray = new unsigned char*[96];
for (int j = 0; j < 96; j++)
{
bitarray[j] = new unsigned char[56];
if (bitarray[j] == NULL)
{
cout << "Memory could not be allocated for 2D Array.";
return;// return if memory not allocated
}
}
bitarray[0][64] = '1';
bitarray[10][64] = '1';
cout << bitarray[0][64] << " " << bitarray[10][64];
getch();
return;
}
The link to the output I get is here (The values are actually assigned accurately, don't know why, though).
In C++, accessing a buffer out of its bounds invokes undefined behavior (not a trapped error, as you expected).
The C++ specification defines the term undefined behavior as:
behavior for which this International Standard imposes no requirements.
In your code, both
bitarray[0][64] = '1';
bitarray[10][64] = '1';
are accessing memory out-of-bound,. i.e., those memory locations are "invalid". Accessing invalid memory invokes undefined behaviour.
The access violation error or segmentation fault is one of the many possible outcomes of UB. Nothing is guaranteed.
From the wiki page for segmentation fault,
On systems using hardware memory segmentation to provide virtual memory, a segmentation fault occurs when the hardware detects an attempt to refer to a non-existent segment, or to refer to a location outside the bounds of a segment, .....
so, maybe, just maybe, the memory area for bitarray[0][64] is inside the allocated page (segment) which is accessible (but invalid anyway) by the program , in this very particular case. That does not mean it will be, always.
That said, void main() is not a correct signature of main() function. The recommended (C++11,ยง3.6.1) signature of main() is int main(void).
C++11 introduced std::array and the method at() provides out of bounds checking.
I have a struct:
typedef struct{
int *issueTypeCount;
}issueTypeTracker;
I've declared a variable of type issueTypeTracker:
issueTypeTracker *typeTracker;
I've allocated necessary memory:
typeTracker = (issueTypeTracker*) malloc(sizeof(issueTypeTracker) * issueTypeList.count());
typeTracker->issueTypeCount = (int*) calloc(65536,sizeof(int));
And then when I try to do something with it, I get a segmentation fault
while(qry.next()){ //while there are records in the query
for(j=0;j<locationList.count();j++){ // no problem
if(qry.value(1) == locationList[j]){ //no problem
for(i=0;i<issueTypeList.count();i++){ //no problem
typeTracker[j].issueTypeCount[i]++; //seg fault as soon as we hit this line
}
}
}
}
I figured it would be a problem with the way i've allocated memory, but as far as I'm aware i've done it correctly. I've tried the solutions proposed in this question, however it still did not work.
I've tried replacing typeTracker->issueTypeCount = (int*) calloc(65536,sizeof(int)); with:
for(j=0;j<issueTypeList.count();j++){
typeTracker[j].issueTypeCount = (int*) calloc(65536,sizeof(int));
}
But I still get the same issue. This happens with any value of j or i, even zero.
This is a lot more trouble than it's worth and a poor implementation of what I'm trying to do anyway, so I'm probably going to scrap this entire thing and just use a multidimensional array. Even so, I'd like to know why this doesn't work, so in the future I don't have trouble when i'm faced with a similar scenario.
You have several issues. Firstly, you're not checking your allocations for success, so any of your pointers could be NULL/nullptr.
Secondly,
typeTracker->issueTypeCount = (int*) calloc(65536,sizeof(int));
is equivalent to
typeTracker[0].issueTypeCount = (int*) calloc(65536,sizeof(int));
so, you initialized the issueTypeCount member for only the first issueTypeTracker in your array. For the other issueTypeList.count() - 1 elements in the array, the pointer is uninitialized.
Therefore this line:
typeTracker[j].issueTypeCount[i]++; //seg fault as soon as we hit this line
will invoke UB for any j>0. Obviously if your allocation failed, you have UB for j==0 as well.
I was working with pointers and was trying different things.
So here I made a general print function
void print(const int &value)
{
cout << "value = " << value << " & address = " << &value << endl;
}
Now Here's a code that works somehow:
int j = 9090;
int* p;
*p = j; //Please read further
print(*p);
I know *p = j is something illogical and I should have done p = &j or p = new int etc.... but why did this work?
The output was
value = 9090 & address = 0x28ff48
Moreover if I print j, the address is 0x28ff44. Which means it allocated new memory automatically for p (as its address is ..48)
Now, if I only add another line before j's declaration:
int i = 80;
int j = 9090;
int* p;
*p = j; //Please read further
print(*p);
^The program crashes.
However if I add this i's line after declaration of p the program runs.
int j = 9090;
int* p;
int i = 80;
*p = j;
print(*p);
Am I doing something wrong? I was using GCC compiler in Dev C++ IDE 4.9.9.2. What's going on?
The problem is that dereferencing an uninitialised pointer is undefined.
This means that anything can happen - sometimes a program will crash, sometimes just give strange results, and sometimes (if you're unlucky) it will just seem to work.
Since your pointer is uninitialised, you will access memory at whatever random location it happens to represent.
Sometimes, this is a valid address, and the program will keep running.
Sometimes, it's an invalid address, and the program will crash.
int* p;
*p = j;
This is correct syntax of C++. It means that in field which address is in p, you put value of j. The problem with crash originate from the fact that you don't provide any memory for p. When you say int * p it means that you have pointer on int variable. However you didn't provide any real address in memory to store int value. There is some rubbish in p but this rubbish is considered to be valid address by program and it tries to write value of j there. If you are lucky and this address was not used the program will work further. Otherwise it will crash. To avoid such undefined behaviour you need to allocate memory for p:
int* p = new int;
*p = j;
I know *p = j is something illogical
In this case it is undefined behavior. You are dereferencing a pointer that wasn't initialized, so it effectively points to an unknown (random) location.
Which means it allocated new memory automatically for p
No, it didn't. The address you see is just the random, undefined value which ended up in your uninitialized pointer.
why did this work?
That's the thing with undefined behavior: It might work by coincidence, for example if the random value in the pointer happened to point into some valid, writable memory region, your code would work fine for that specific run. Another time, it might just crash. Yet another time, it might corrupt your heap, or some unrelated data, and cause a seemingly unrelated crash or bug some time later. Which is just screaming for long nights in front of your debugger ;)
Bottom line: Don't do it - avoid UB at all cost.
However if I add this i's line after declaration of p the program runs.
I think the behavior you observe (crash vs. no crash) is not directly related to the code changes, but coincidental. In fact, if you'd run the "working" version multiple times, I'm sure you'd still get a crash after some time.
I started learning C++ and I wanted to implement a simple 2D array and get its size without using std::vector. However I run into weird errors with my second dimension:
int **data= new int*[2];
for (int i = 0; i<2;i++){
data[i] = new int[3];
}
data[0][0] = 1;
data[0][1] = 2;
data[0][2] = 3;
data[1][0] = 4;
data[1][1] = 5;
data[1][2] = 6;
data[1][25] = 20; //Should segfault? AAAAA
cout << "Data[1][25] = " << data[1][25] << endl; //Should segfault, no?
int n = sizeof(data[0]) / sizeof(int);
int m = sizeof(data) / sizeof(int);
cout << "M is " << m << " N is " << n << endl;// Reports m = 2, n =2?!?!? BBBB
At AAAA I should be getting segfault, no? Instead I am able to assign a value and later read it. The value of data[1][any] is zero, like it has been initialized. This is only a problem in the second dimension, the first dimension behaves as expected.
Later at BBBB I am not getting an accurate size for n. Am I doing something wrong?
C++ does not do bound checking on arrays. Accessing data outside the bounds of an array is undefined behavior and anything can happen. It may cause a segfault it might not. If you have valid memory regions before or after the array you can end up accessing or modifying that memory instead. This can lead to corruption of other data used by your program.
Also you use of sizeof is incorrect. sizeof is a compile time construct. It cannot be used to determine the size of an array through a pointer value at runtime. If you need that type of functionality use std::array or std::vector.
char somearray[10];
int size = sizeof(somearray); // result is 10. Yay it works.
char *somearrayptr = new char[10];
int size = sizeof(somearrayptr); // size = the size of char* not char[10].
At AAAA you have undefined behavior. Just anything can happen from that point on -- and more interesting, even before.
In standard C++ there is no such behavior as 'segfault'. And implementation could define some operations to do that but I'm not aware if any ever bothered. It just happens by chance for some cases.
Accessing an array outside its boundaries is undefined behavior. So there is no reason to expect anything in particular will happen: it could crash, return the right answer, return the wrong answer, silently corrupt data in another part of the program, or a whole host of other possibilities.
data[1][25] = 20; //Should segfault? AAAAA
It would segfault if you are not allowed to access the location. There is no checking in C++ to see if the location you are accessing is valid frrm the code-point of view.
You obtained an output because that was stored at that location. It could have been anything. This is undefined behaviour and you may not get the same result everytime.
See this answer, though it talks abput local variables , but it gives nice examples about how such accessing of data can be undefined behaviour
data and data[0] are both pointers (doesn't matter single or double). They have a defined size for every implementation. In your case, size of pointer is twice that of size of int on your machine. Hence, the output. sizeof when used with pointers pointing to arrays (and not arrays i.e. ones declared as arrays char a[] etc) gives the size of the pointer
Both data[0] and data are pointers. Pointers will be size 4 on a 32-bit system, and 8 on a 64-bit system. Therefore, m and n are equal. Size of int is always 4.
According to the correct answer in Static array vs. dynamic array in C++ static arrays have fixed sizes.
However, this compiles and runs just fine:
int main(int argc, char** argv) {
int myArray[2];
myArray[0] = 0;
myArray[1] = 1;
cout<<myArray[0]<<endl;
cout<<myArray[1]<<endl;
myArray[4];
myArray[2] = 2;
myArray[3] = 3;
cout<<myArray[2]<<endl;
cout<<myArray[3]<<endl;
return 0;
}
Does this mean a static array can be resized?
You're not actually enlarging the array. Let's see your code in detail:
int myArray[2];
myArray[0] = 0;
myArray[1] = 1;
You create an array of two positions, with indexes from 0 to 1. So far, so good.
myArray[4];
You're accessing the fifth element in the array (an element which surely does not exist in the array). This is undefined behaviour: anything can happen. You're not doing anything with that element, but that is not important.
myArray[2] = 2;
myArray[3] = 3;
Now you are accessing elements three and four, and changing their values. Again, this is undefined behaviour. You are changing memory locations near to the created array, but "nothing else". The array remains the same.
Actually, you could check the size of the array by doing:
std::cout << sizeof( myArray ) / sizeof( int ) << std::endl;
You'll check that the size of the array has not changed. BTW, this trick works in the same function in which the array is declared, as soon you pass it around it decays into a pointer.
In C++, the boundaries of arrays are not checked. You did not receive any error or warning mainly because of that. But again, accessing elements beyond the array limit is undefined behaviour. Undefined behaviour means that it is an error that may be won't show up immediately (something that is apparently good, but is actually not). Even the program can apparently end without problems.
No, not a chance in hell. All you've done is illegally access it outside it's bounds. The fact that this happens to not throw an error for you is utterly irrelevant. It is thoroughly UB.
First, this is not a static array, it is an array allocated in the automatic storage.
Next, the
myArray[4];
is not a new declaration, it is a discarded read from element #4 of the previously declared 2-element array - an undefined behavior.
Assignments that follow
myArray[2] = 2;
myArray[3] = 3;
write to the memory that is not allocated to your program - an undefined behavior as well.