Programs partition their memory into functional groups, allocating memory for new data (i.e., variables) from two of them. Programs allocate memory for automatic variables on the stack and dynamic variables on the heap. The algorithms managing the stack and heap are different:
The program always allocates stack memory on the stack's top and deallocates it in the reverse allocation order.
The program allocates heap memory with the new operator, which searches the heap for a contiguous block large enough to satisfy the request, subdivides the block, and returns the address of the newly allocated memory. It can deallocate memory in any order with the delete operator, which coalesces adjacent freed blocks.
C++ Code
Abstract Representation
(a)
int counter = 123;
int* cntptr = &counter;
(b)
(c)
cout << counter << endl;
(d)
cout << *cntptr << endl;
Automatic (stack) pointer variables and operators. Demonstrates the pointer-definition, address-of, and dereference operators with simple C++ statements and contrasts the statements with abstract representations of how the variables appear in main memory and react to the operators.
Defines and initializes an integer variable named counter and a pointer variable named cntptr. The variable definitions allocate memory. Each variable has a name, contents, and an address. In this example, the address-of operator, &, forms an expression whose value is the address of its operand, counter. The second assignment operation saves cntptr's address in counter.
An alternate view of (a) with an arrow from the pointer variable, cntptr, to the data variable, counter. The arrow replaces the arbitrary and unknown address in the first illustration.
The computer goes to the address corresponding to counter, loads the value saved at that location, and prints it to the console, accessing memory once.
The expression *cntptr demonstrates the indirection or dereference operator by printing the contents of counter indirectly through the pointer variable cntptr. The computer goes to the memory address corresponding to cntptr, retrieves the address saved there, goes to the retrieved address, loads the value saved there, and prints it to the console. Thus accessing a variable's content without using its name. Accessing the content of one variable indirectly through another variable takes two trips to memory, is called dereferencing, and can only be done with a pointer variable.
(a)
int* ip = new int;
(b)
int* ia = new int[100];
(c)
Person* p = new Person;
(d)
cout << *ip << endl;
(e)
cout << ia[5] << endl;
(f)
p->name;
p->pay_taxes();
(g)
delete ip;
(h)
delete[] ia;
(i)
delete p;
Allocating, using, and deallocating dynamic memory. The new operator allocates memory on the heap and returns its address; programs typically store the address in a pointer variable. Various pointer operators allow programmers to manipulate or use the memory. The memory remains allocated until the programmer explicitly deallocates it with the delete operator.
Allocating memory for a single, small data type (an int in this example) on the heap is rare.
Allocating memory for an array on the heap is common; the array size can be determined at runtime (i.e., the size can be a variable).
Assuming Person names a class, the example demonstrates allocating memory for an object on the heap.
Dereferencing a pointer pointing to memory on the heap; the dereference operation is the same for memory allocated on the stack (compare with Figure 1(d))
The index operator, [], operates on an address. Programmers often use it with automatic arrays allocated on the stack. But they can also use it with pointers pointing to dynamic arrays allocated on the heap.
The arrow operator, ->, selects the data and the functions of an object
Deallocating and returning the memory for a single data item to the heap.
Deallocating and returning the memory for an array to the heap; the brackets at the end of "delete" are necessary to call the destructor (introduced in Chapter 9) for each object in the array
Deallocating and returning the memory for an object to the heap.
The delete operator, (g), (h), and (i), does not change the address saved in the pointer variable. So, the pointer still points to the deallocated memory following the deletion, but programs should not use or access that memory in any way.