tags:

views:

440

answers:

11

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;
}
+17  A: 

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.

RichieHindle
FYI - By "fail", he means the code will still work, but it'll give you unpredictable results. Which is usually worse than just failing in the traditional sense (segmentation fault, etc.)
Eric Petroelje
Or if, on certain operating systems, an interrupt goes off or you receive a signal. It can be one of those intermittent bugs that is *very* hard to track down.
keraba
Or if the return causes the stack to shrink enough that a page may be unloaded by the OS. Then attempting to access the page may cause a seg fault.
Martin York
+6  A: 

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)

Eric Petroelje
+2  A: 

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.

Artem Barger
Not what the OP was asking, but this is indeed the correct/reliable way to do it.
Noldorin
No, the correct and reliable way to do it is to use a std::vector.
anon
std::vector will invoke allocation and deallocation undercover for you, I just pointed, that you cannot return the local variable from function call since there is a difference between stack and heap variables.
Artem Barger
+2  A: 

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.

sharptooth
First answer I found as I scrolled down the page that mentioned the stack.
Rob K
+1  A: 

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.

jalf
+7  A: 

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.

anon
Is it *really* illegal C++? I don't really know C++, but the line certainly looks like valid C...
Noldorin
It's valid C99. It would be valid C++ if Sum was a constant, but it is a variable.
anon
oh, nice find. I hadn't spotted that.
jalf
+1 on "anything could happen - it could even appear to work."
Javier
works fine with GCC on OSX.
Dave Gamble
A: 

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
schnaader
+2  A: 

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.

Lou Franco
+1  A: 

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.

ChrisW
A: 

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.

Thomas L Holaday
A: 

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.

Rob K