#include<iostream.h>
#include<conio.h>
int *p;
void Set()
{
int i;
i=7;
p=&i;
}
int Use()
{
double d;
d=3.0;
d+=*p;
//if i replace the above 3 statements with --> double d=3.0+*p; then output is 10 otherwise the output is some random value(address of random memory location)
//why is this happening? Isn't it the same?
return d;
}
void main()
{
clrscr();
Set();
cout<<Use();
getch();
}
My question is as mentioned in comments above.I want to know the exact reason for the difference in outputs.In the above code output is some address of random memory location and i understand that is because of i is a local variable of Set() but then how is it visible in the second case that is by replacing it with double d=3.0+*p; because then the output comes 10( 7+3 ) although 7 should not have been visible?
The result of using pointer p is undefined, it could also give you a segfault or just return 42. The technical reason behind the results your'e getting are probably:
i inside Set is placed on the stack. The value 7 ist stored there and p points to that location in memory. When you return from Set value remains in memory: the stack is not "destroyed", it's just the stack pointer which is reset. p still points to this location which still contains the integer representation of "3".
Inside Use the same location on the stack is reused for d.
When the compiler is not optimizing, in the first case (i.e. the whole computation in one line), it first uses the value 7 (which is still there in memory with p pointing to it), does the computation, overwrites the value (since you assign it to d which is at the same location) and returns it.
In the second case, it first overwrites the value withe the double value 3.0 and then takes the first 4 bytes interpreted as integer value for evaluating *p in d+=*p.
This case shows why returning pointers/references to local variables is such a bad thing: when writing the function Set you could even write some kind of unit tests and they would not detect the error. It might get unnoticed just until the software goes into production and has to perform some really critical task and just fails then.
This applies to all kindes of "undefined behaviour", especially in "low level" languages like C/C++. The bad thing is that "undefined" may very well mean "perfectly working until it's too late"...
After exiting function Set the value of pointer p becomes invalid due to destroying local variable i. The program has undefined behavior.
Related
I am in learning about pointers and strings and how they work. I have a question which answer may I know already. But, in fact, I want to be sure of it.
Let take the following code for example:
char a[200],*p;
gets(a); // cin.get(a,200);
p=a;
strcpy(p,p+1);
printf("%s",a); // c
cout<<a; // cpp
return 0;
Input : working
Output : orking
So what about this? Why do the array modified without actually modify itself?
char a[200],*p;
gets(a); // cin.get(a,200);
p=a;
p++;
printf("%s",a); // cout<<a;
return 0;
Input : working
Output : working
In this case, why the array did not modify? What has the function strcpy special? And which other functions has this propriety?
Throughout the text, I have referred to the functions of the strings set in the program.
Snippet 1
char a[200],*p;
Defined a block of 200 characters ,a, and a pointer, p, to a block of one or more characters.
gets(a); // cin.get(a,200);
Read some user input into memory block a
p=a;
Points p at block a. p can now be used as a reference to the same thing as a
strcpy(p,p+1);
Copy part of the memory block over itself. NOTE: this invokes undefined behaviour because the to and from buffers in strcpy overlap (See http://en.cppreference.com/w/cpp/string/byte/strcpy). The results may be unusual, ranging from "Looks like it works!" to more fantastic, such as the computer making it rain unicorns.
So, say a is created at memory location 10. Data is read into the block starting at location 10. Then p is set to point at location ten. Then the memory starting at location 11 is copied over the memory starting at location 10. Since a is at 10, printing a prints the altered data. Since p is still pointing at 10, printing p will print the same thing as a.
Snippet 2:
char a[200],*p;
Defined a block of 200 characters ,a, and a pointer, p, to a block of one or more characters.
gets(a); // cin.get(a,200);
Read some user input into memory block a
p=a;
Points p at block a. p can now be used as a reference to the same thing as a
p++;
Moved where p pointed over one slot to the right. Copied nothing. Just changed the address that p points at.
So, say a is created at memory location 10. Data is read into the block starting at location 10. Then p is set to point at location 10. Then p is set to point at memory location 11. The values in memory block a are unchanged. Since a is still at 10, printing a prints the unchanged data. Since p is now pointing at 11, printing p will print the from the second character of a onward.
You are not modifying anything in the second code. Why should it be modified?
Piano points to the first element of a. Then you increment it. So please points to the second element. Then you print a, who wasn't modified.
As for the first one, from strcpy reference :
To avoid overflows, the size of the array pointed by destination shall be long enough to contain the same C string as source(including the terminating null character), and should not overlap in memory with source
I think you have what is called an overlap.
You copy a source to a destination that's overlapping in memory.
I am a c++ learner. Others told me "uninitiatied pointer may point to anywhere". How to prove that by code.?I made a little test code but my uninitiatied pointer always point to 0. In which case it does not point to 0? Thanks
#include <iostream>
using namespace std;
int main() {
int* p;
printf("%d\n", p);
char* p1;
printf("%d\n", p1);
return 0;
}
Any uninitialized variable by definition has an indeterminate value until a value is supplied, and even accessing it is undefined. Because this is the grey-area of undefined behaviour, there's no way you can guarantee that an uninitialized pointer will be anything other than 0.
Anything you write to demonstrate this would be dictated by the compiler and system you are running on.
If you really want to, you can try writing a function that fills up a local array with garbage values, and create another function that defines an uninitialized pointer and prints it. Run the second function after the first in your main() and you might see it.
Edit: For you curiosity, I exhibited the behavior with VS2015 on my system with this code:
void f1()
{
// junk
char arr[24];
for (char& c : arr) c = 1;
}
void f2()
{
// uninitialized
int* ptr[4];
std::cout << (std::uintptr_t)ptr[1] << std::endl;
}
int main()
{
f1();
f2();
return 0;
}
Which prints 16843009 (0x01010101). But again, this is all undefined behaviour.
Well, I think it is not worth to prove this question, because a good coding style should be used and this say's: Initialise all variables! One example: If you "free" a pointer, just give them a value like in this example:
char *p=NULL; // yes, this is not needed but do it! later you may change your program an add code beneath this line...
p=(char *)malloc(512);
...
free(p);
p=NULL;
That is a safe and good style. Also if you use free(p) again by accident, it will not crash your program ! In this example - if you don't set NULL to p after doing a free(), your can use the pointer by mistake again and your program would try to address already freed memory - this will crash your program or (more bad) may end in strange results.
So don't waste time on you question about a case where pointers do not point to NULL. Just set values to your variables (pointers) ! :-)
It depends on the compiler. Your code executed on an old MSVC2008 displays in release mode (plain random):
1955116784
1955116784
and in debug mode (after croaking for using unitialized pointer usage):
-858993460
-858993460
because that implementation sets uninitialized pointers to 0xcccccccc in debug mode to detect their usage.
The standard says that using an uninitialized pointer leads to undefined behaviour. That means that from the standard anything can happen. But a particular implementation is free to do whatever it wants:
yours happen to set the pointers to 0 (but you should not rely on it unless it is documented in the implementation documentation)
MSVC in debug mode sets the pointer to 0xcccccccc in debug mode but AFAIK does not document it (*), so we still cannot rely on it
(*) at least I could not find any reference...
Look at this program:
#include <iostream>
using namespace std;
int main()
{
const int x = 0;
int *p;
p=(int*)&x;
(*p)++;
cout<<x<<endl;
cout<<*p;
}
As you see above, I declared x as a const int, and using casting, a non const pointer named p is points to it. In the middle of the body of my program, I increased the value of x by one using (*p)++ (How is it possible, while x is defined as const?)
Now,when I print *p and x, they returns different values, while *p is supposed to point to address of x :
ap1019#sharifvm:~$ ./a.out
0
1
Why?
The change of variable after constant removal causes the undefined behaviour, in some cases it will just work as if it wouldn't be const, in some it will cause the memory violation error, in some, it will turn your computer into the rabbit which will try to kill you...
A bit of background on the behaviour. Imagine you are a compiler. You encounter the variable:
const int blah = 3;
And then you encounter the following operation:
int foo = 4 + blah;
As you are smart compiler and you know that blah is constant - therefore it will not change, instead of reading the value from the blah, you can exchange the value from get the blah storage place in memory read it to simply add the 3 to 4 and assign it to foo.
Infant you will probably assign 7 straight away because doing the addition is pointless each time you run the program.
Lets now get into the casting away the const part.
Some really sneaky programmer is doing the following:
int * blah_pointer = (int *) & blah;
Then he is increasing the blah value by doing this operation:
(*blah_pointer)++;
What will happen - if the variable is not in the protected memory (not read only) the program will just increase the value of variable stored in memory.
Now when you will read the value which is stored in the pointer you will get the increased value!
Ok but why is there an old, unchanged value if you are reading just the blah I hear you ask:
std::cout << blah;
It is there, because the compiler try to be smart and instead of actually reading the value from blah it will just exchange it to a constant value to blah, so instead of reading it it will actually exchange it to std::cout << 3.
The undefined part is changing the constant value - you can't ever know whether the value will be stored in protected or unprotected region therefore you can't tell what will happen.
If you want the compiler to actually check the value each time it encounters it just change the definition from:
const int blah = 3;
to
const volatile int blah = 3;
It will tell the compiler the following, even though the program I am writing is not allowed to change the blah value, it may be changed during the execution of the program, therefore do not try to optimise the access to the memory and read it every time the value is used.
I hope this makes it clearer.
I think, in compilation step, your compiler will replace all your constant variables with its values (it's like #define), it's the way GNU GCC compiler optimize the code.
I'm not 100% sure about it, but i've got the same issue while learning C/C++ syntax, and it's the conclusion that i've made after disassebling (converting the binary executable to assembler code) my program.
Anyways, just try to disassemble your output and see what is really happening.
For some reason in my c++ code, int i= 0 is not working. In debug mode, it stores 1024 into i after it goes out of scope. When I try to declare it to 0, it doesn't work. i is not a global variable.
void CCurrent::findPeaks()//this checks for peaks in the FFT
{
int localPeakIndx[256]={};
int j=0;
for(int i=0;i<DATASIZE/2;i++)
{
if(magnitude[i]>m_currentValues.AverageMagnitude*3) {
localPeakIndx[j]=i;
j++;
}
}
//i should be out of scope
int startIndx;
int endIndx;
int i = 0;//why does it equal 1024?????? debug*
It is not clear what you mean by "int i= 0 is not working" and "it stores 1024 into i after it goes out of scope". That description is unrealistic and most likely does not take place. After int i = 0 the value of i will be seen as 0, not as 1024.
What you have to keep in mind in this case is that your program has two i variables: one local to for cycle and one declared further down in the surrounding block. These are two different, completely unrelated variables.
Now, MS Visual Studio debugger will show you the values of all variables declared in the current block, even if the execution has not yet reached their point of declaration. Expectedly, variables whose declaration (and initialization) point has not been reached yet are shown with indeterminate (uninitialized) values.
Apparently, this is exactly what happens in your case. Your are looking at the value of outer i before its point of declaration and initialization. Even though name i is not yet visible immediately after the for cycle from the language point of view, the debugger will nevertheless give you "early access" to the outer i. The garbage value of that i at that point just happened to be 1024 in your experiment.
Note that there's certain definitive logic in this behavior. In general case it is not correct to assume that a local object does not exist above the point of its declaration. Being located above the point of declaration in spatial terms does not necessarily mean being located before the point of declaration in temporal terms, which becomes clear once you start using such beautiful feature of the language as goto.
For example, this piece of code
{
int *p = NULL;
above:
if (p != NULL) {
std::cout << *p << std::endl;
goto out;
}
int i = 10;
p = &i;
goto above;
out:;
}
is legal and has perfectly defined behavior. It supposed to output the valid initialized value of i through a valid pointer p, even though the output takes place above the i's point of declaration. I.e. it is possible to end up in the situation when the current execution point is located above the object declaration, yet the object already exists and holds a determinate value. To help you with debugging in such situations the debugger allows you to see the values of all objects that may potentially exist at that point, which includes all objects declared in the current block. In general case the debugger does not know which objects formally exist already and which do not, so it just lets you see everything.
Just a small refinement of what was already said:
The "outer i" is given space on the stack along with all other local variables when the function is entered.
Since the "outer i" hasn't been given a value before the end of the for loop, the debugger is looking on the stack where the value for i ought to be, and showing you what happens to be there.
This comes from the fact that local variables are not initialized.
I bet if you tried to access i from C before the declaration, the compiler would tag that as an error. But the debugger doesn't have such scruples.
Doesn't the space occupied by a variable get deallocated as soon as the control is returned from the function??
I thought it got deallocated.
Here I have written a function which is working fine even after returning a local reference of an array from function CoinDenom,Using it to print the result of minimum number of coins required to denominate a sum.
How is it able to print the right answer if the space got deallocated??
int* CoinDenom(int CoinVal[],int NumCoins,int Sum) {
int min[Sum+1];
int i,j;
min[0]=0;
for(i=1;i<=Sum;i++) {
min[i]=INT_MAX;
}
for(i=1;i<=Sum;i++) {
for(j=0;j< NumCoins;j++) {
if(CoinVal[j]<=i && min[i-CoinVal[j]]+1<min[i]) {
min[i]=min[i-CoinVal[j]]+1;
}
}
}
return min; //returning address of a local array
}
int main() {
int Coins[50],Num,Sum,*min;
cout<<"Enter Sum:";
cin>>Sum;
cout<<"Enter Number of coins :";
cin>>Num;
cout<<"Enter Values";
for(int i=0;i<Num;i++) {
cin>>Coins[i];
}
min=CoinDenom(Coins,Num,Sum);
cout<<"Min Coins required are:"<< min[Sum];
return 0;
}
The contents of the memory taken by local variables is undefined after the function returns, but in practice it'll stay unchanged until something actively changes it.
If you change your code to do some significant work between populating that memory and then using it, you'll see it fail.
What you have posted is not C++ code - the following is illegal in C++:
int min[Sum+1];
But in general, your program exhibits undefined behaviour. That means anything could happen - it could even appear to work.
The space is "deallocated" when the function returns - but that doesn't mean the data isn't still there in memory. The data will still be on the stack until some other function overwrites it. That is why these kinds of bugs are so tricky - sometimes it'll work just fine (until all the sudden it doesn't)
You need to allocate memory on the heap for return variable.
int* CoinDenom(int CoinVal[],int NumCoins,int Sum) {
int *min= new int[Sum+1];
int i,j;
min[0]=0;
for(i=1;i<=Sum;i++) {
min[i]=INT_MAX;
}
for(i=1;i<=Sum;i++) {
for(j=0;j< NumCoins;j++) {
if(CoinVal[j]<=i && min[i-CoinVal[j]]+1<min[i]) {
min[i]=min[i-CoinVal[j]]+1;
}
}
}
return min; //returning address of a local array
}
min=CoinDenom(Coins,Num,Sum);
cout<<"Min Coins required are:"<< min[Sum];
delete[] min;
return 0;
In your case you able to see the correct values only, because no one tried to change it. In general this is unpredictable situation.
That array is on the stack, which in most implementations, is a pre-allocated contiguous block of memory. You have a stack pointer that points to the top of the stack, and growing the stack means just moving the pointer along it.
When the function returned, the stack pointer was set back, but the memory is still there and if you have a pointer to it, you could access it, but it's not legal to do so -- nothing will stop you, though. The memory values in the array's old space will change the next time the stack depth runs over the area where the array is.
The variable you use for the array is allocated on stack and stack is fully available to the program - the space is not blocked or otherwise hidden.
It is deallocated in the sense that it can be reused later for other function calls and in the sense that destructors get called for variables allocated there. Destructors for integers are trivial and don't do anything. That's why you can access it and it can happen that the data has not been overwritten yet and you can read it.
The answer is that there's a difference between what the language standard allows, and what turns out to work (in this case) because of how the specific implementation works.
The standard says that the memory is no longer used, and so must not be referenced.
In practice, local variables on the stack. The stack memory is not freed until the application terminates, which means you'll never get an access violation/segmentation fault for writing to stack memory. But you're still violating the rules of C++, and it won't always work. The compiler is free to overwrite it at any time.
In your case, the array data has simply not been overwritten by anything else yet, so your code appears to work. Call another function, and the data gets overwritten.
How is it able to print the right answer if the space got deallocated??
When memory is deallocated, it still exists, but it may be reused for something else.
In your example, the array has been deallocated but its memory hasn't yet been reused, so its contents haven't yet been overwritten with other values, which is why you're still able from it the values that you wrote.
The fact that it won't have been reused yet is not guaranteed; and the fact that you can even read from it at all after it's deallocated is also not guaranteed: so don't do it.
This might or might not work, behaviour is undefined and it's definitely wrong to do it like this. Most compilers also give a compiler warning, for example GCC:
test.cpp:8: warning: address of local variable `min' returned
Memory is like clay that never hardens. Allocating memory is like taking some clay out of the clay pot. Maybe you make a cat and a cheeseburger. When you have finished, you deallocate the clay by putting your figures back into the pot, but just being put into the pot does not make them lose their shape: if you or someone else looks into the pot, they will continue to observe your cat and cheeseburger sitting on the top of the clay stack until someone else comes along and makes them into something else.
The NAND gates in the memory chips are the clay, the strata that holds the NAND gates is the clay pot, and the particular voltages that represent the value of your variables are your sculptures. Those voltages do not change just because your program has taken them off the list of things it cares about.
You need to understand the stack. Add this function,
void f()
{
int a[5000];
memset( a, 0, sizeof(a) );
}
and then call it immediately after calling CoinDenom() but before writing to cout. You'll find that it no longer works.
Your local variables are stored on the stack. CoinDenom() returns a memory address that points into the stack. Very simplified and leaving out lots of details, say the stack pointer is pointing to 0x1000 just before you call CoinDenom. An int* (Coins) is pushed on the stack. This becomes CoinVal[]. Then an int, Num which becomes NumCoins. Then another int, Sum which becomes Sum. Thats 3 ints at 4 bytes/int. Then space for the local variables:
int min[Sum+1];
int i,j;
which would be (Sum + 3) * 4 bytes/int. Say Sum = 2, that gives us another 20 bytes total, so the stack pointer gets incremented by 32 bytes to 0x1020. (All of main's locals are below 0x1000 on the stack.) min is going to point to 0x100c. When CoinDenom() returns, the stack pointer is decremented "freeing" that memory but unless another function is called to have it's own locals allocated in that memory, nothing's going to happen to change what's stored in that memory.
See http://en.wikipedia.org/wiki/Calling_convention for more detail on how the stack is managed.