Trying to understand stack and heap in C++
I am pretty new to C++ and trying to understand the concept of stack and heap as much as I can (or at least as much as I need to know). Some people tend to say that a starter shouldn't bother that much but it seems to me that a memory leak or stack overflow can occur pretty easily. I have been reading some stuff but I am still a little confused and unsure if I got it right.
Here is what I got so far...
1. The heap :
The heap is a shared and dynamically alocated area. It can be accessed by any part of our process with the right pointer and knowledge of content (type and length). If we try to use wrong pointers (trivial address or pointer to deallocated) will result in segmentation faults. Accessing a bigger content than what's been allocated will also result in a segmentation fault (for example trying to read a bigger array than what was allocated). Unused areas have to be "manually" deallocated to avoid memory leaks
2. The stack :
The stack is the part of memory where parameters and local variables are allocated. The stack is limited in size. The stack works as a LIFO (Last In First Out).
Let's say the stack is a bin of a predefined size (stack size). When we define local variables they are put on the stack (into the bin) and as soon the scope changes (for example a function is called) a platter is used in our bin preventing access to the variables defined in previous scopes and a new local scope is created. Once a function ends all local variables are destroyed and the platter in our bin is removed (returning to the previous scope).
Example :
void MyFunction()
{
int *HeapArray = new int[10];
// HeapArray is assigned 40 bytes from the heap
// *HeapArray is assigned 4 bytes from the stack in a 32 bit environment
int StackArray1[10];
// StackArray is assigned 40 bytes from the stack
int StackArray2[20];
// StackArray is assigned 80 bytes from the stack
HeapArray = StackArray2;
// segmentation fault because StackArray it too large
delete HeapArray;
// this will deallocate the area assigned in the heap
// omitting delete would result in memory leaks
// the pointer itself *HeapArray continues to exist in the stack
HeapArray = StackArray1;
// segmentation fault because HeapArray is pointing to deallocated memory
MyFunction();
// this will result in a stack overflow
}
Questions :
Q1. Defining a local variable that is too big for the stack or having a endless recursive function like in my example above gives me a segmentation fault. Why isn't this saying 'stack overflow'? Is it because the stack is "overflowing into the heap" and creating segmentation faults?
Q2. Assuming the example of the bin and platters I gave for the stack : when using extern
is the content copied to the new scope on top of the last platter or is some kind of pointer created?
The code you've posted is full of bugs, but not just the ones you list in the comments. To being with, plain C style arrays are not assignable. So, the following line is not copying the contents of the array on the right side to the array on the left side.
HeapArray = StackArray2;
C, and C++, allow an implicit conversion from an array to a pointer pointing to the first element of the array; this is commonly known as decaying to a pointer to the first element. Hence, the statement above causes the HeapArray
pointer to point to the beginning of StackArray2
. Then, when you call delete
on HeapArray
, you're trying to delete
memory that was not new
ed. This is undefined behavior, and will crash your program (if you're lucky).
In addition to that, you've also leaked the memory you allocated via new
, because you've now lost the only pointer to that memory.
Similarly, the next assignment to HeapArray
is assigning the address of StackArray1
to HeapArray
. Because you're only assigning pointers, there is no error on this line; the program will continue executing fine (but you've probably already crashed due to the previous deletion).
To answer your questions -
1 - There's no guarantee overflowing the stack, or erroneous deletions, will always fail in a predictable manner. It also depends on the compiler you're using. If I comment out all code in MyFunction()
, except for the recursive call to itself, g++ 4.8 issues no warnings, and fails with a segmentation fault. However, VS2012 issues a warning
warning C4717: 'MyFunction' : recursive on all control paths, function will cause runtime stack overflow
and fails at runtime stating
Unhandled exception at 0x00062949 in Test.exe: 0xC00000FD: Stack overflow (parameters: 0x00000001, 0x00802FA4)
However, that was with optimizations disabled. With optimizations enabled, the program runs endlessly (with both compilers). This is probably because the code is trivial enough that the recursive call to self was replaced by an infinite loop by both compilers. Now there won't ever be a stack overflow, but your program will never terminate either.
2 - Global variables (the ones you extern
to access from another translation unit) are not stored on the stack. They are stored in an implementation defined area of memory that is distinct from the stack.
Q1. what happens is called stack overflow but the effect is that you are going outside the allowed memory for the stack hence you are trying to access something that you can't access, so it's technically a segmentation fault.
Q2. your example doesn't fit because the stack doesn't hide any previous content, any pointer that points to anything which is deeper in the stack is still valid, it doesn't get hidden by a successive call. It's called a stack because it behaves like a stack (with the data allocated which grows on the top of it) but anything which is below is just memory and can be legally accessed if you keep a pointer to it.
Just an additional note, the call stack contains also the activation records of the function calls, which are used to be able to return from them correctly.
链接地址: http://www.djcxy.com/p/79108.html上一篇: (C ++)堆上的内存变为可访问/被删除
下一篇: 试图理解C ++中的堆栈和堆