We briefly described the memory segments in Section 9.1—text, data, stack, and heap. Variables can be allocated in all but the text segment. Data can be stored in the text segment, but since it is read only, the data is in a fixed memory location and remains constant throughout execution of the program. It cannot be changed by an application program.
Data stored in the data segment can be either variable or constant. It remains in a fixed memory location throughout program execution. That location may be globally known to all the functions in the program, or it may be restricted to a subset of the functions, depending on the scoping rules of the language.
In Section 10.5 you learned that local variables allocated on the stack are effectively created during the execution of the prologue when the function is first entered, and then deleted during the execution of the epilogue the end of the function by moving the stack pointer. Even though moving the stack pointer does not change the contents of memory in the area “above” the stack pointer, you have no way of knowing whether some other mechanism has changed this area of memory, so it is a programming error to access any of these local variables once the function has terminated. They can be located at different memory locations each time they are created, depending on the state of the stack when the function is called. These are often called automatic variables.
The heap is another source of memory for storing variables in your program. Memory from the heap is allocated under program control. For example, the malloc() function in C, or the new operator in C++, allocate memory from the heap. The amount of memory available from the heap is much greater than that on the stack, so the heap is more suitable for large data structures like large arrays. Unlike memory allocated on the stack, memory allocated from the heap remains allocated until the program explicitly deallocates it. There is nothing about the function entry/exit protocol that would release heap memory.
The persistence of heap memory between function calls can be very important if, for example, your program needs to call several functions to operate on a large data set. All you need do is to pass the address of the variable on the heap to each of the processing functions.
On the other hand, this persistence of allocated heap memory is also responsible for one of the more common program bugs—a memory leak. The programmer must remember to call a function to deallocate the heap memory when it is no longer needed. If not, and the function that allocates it is called multiple times, new memory areas are allocated from the heap each call. Eventually, the memory limits of the system are reached.