Did the author make a mistake in explaining stack and heap in C++ or am I misreading something?

Here is the code:

int main()
{
    using namespace std; 
    int nights = 1001; 
    int * pt = new int; // allocate space for an int
    *pt = 1001;         // store a value there

    cout << "nights value = ";
    cout << nights << ": location " << &nights << endl;
    cout << "int ";
    cout << "value = " << *pt << ": location = " << pt << endl;

    double * pd = new double; // allocate space for a double
    *pd = 10000001.0; // store a double there

    cout << "double ";
    cout << "value = " << *pd << ": location = " << pd << endl; 
    cout << "location of pointer pd: " << &pd << endl;
    cout << "size of pt = " << sizeof(pt);
    cout << ": size of *pt = " << sizeof(*pt) << endl;
    cout << "size of pd = " << sizeof pd;
    cout << ": size of *pd = " << sizeof(*pd) << endl;

    return 0;
}

Now here is the author's note about the code:

Another point to note is that typically new uses a different block of memory than do the ordinary variable definitions that we have been using. Both the variable nights and pd have their values stored in a memory region called the stack, whereas the memory allocated by the new is in a region called the heap or free store.


Initial Question:

Now my concern is this: the variable pd was create by the keyword new, so it should be stored in the region called heap just like the variable pt, since they were both created by the keyword new.

Am I missing something here? Thank you very much in advance for your inputs.

Revised Question/Follow-up based on the hold:

This question was put on hold by 5 people because they couldn't understand what I was asking. I believe that my question has already been answered but for those who are still not sure about what I was initially asking please read along:

I was unclear about the author's explanation about where the variables and their values were stored in memory. Up to the author explanation, I had a belief that any memory created dynamically (or should I say during runtime after compiling) by using the keyword new gets stored in the heap not the stack.

So, it confused me when he wrote that the variable pd has is value stored in the stack, but again how is that possible if the variable was create during "runtime" with the keyword new, so it should be in the heap, not the stack.

Please try to use the code above as the reference and in particular the **variables (nights, pd, and pt) in your answer so that I can understand it from that code's perspective.


The pointer variables pt and pd are stored on the stack. The values they point at, allocated with new, are stored on the heap.

If I write a sign with an arrow labelled "lake", it doesn't mean that the sign itself is a lake, nor that it must be mounted in a lake. Rather, it should be mounted on solid ground, pointing in the direction of the lake.


The only mistakes the author have made are

  1. Not calling delete once use of the pointers is finished.

  2. The repeated use of endl is questionable. Use \n instead.

  3. using namespace std;, whilst often used in tutorials to achieve brevity is ill-advised in production code, particularly in headers.

  4. Using int * pt = new int; *pt = 1001; in place of int* pt = new int(1001); is questionable since the way the author has it, *pt is in an unnecessarily uninitialised state between two statements. That makes your code vulnerable to instabilities to creep in.

  5. (Minor). You should always think about the possibility that new can throw a std::bad_alloc exception if the allocation fails.

I wouldn't worry about the terms stack and heap too much; they are language implementation concepts not part of the language itself. Prefer the terms automatic and dynamic storage duration. That's what the C++ standard uses, so why invent a whole load of alternative terminology?

Really I'd burn the book and get yourself a copy of Stroustrup.


Pictures will help.

Automatic storage (stack)                      Dynamic storage (heap)
-------------------------                      ----------------------

Item        Address        Value               Address        Value
----        -------        -----               -------        -----          
nights      0xff001000     1001               
    pt      0xff001004     0x00b0fff0 ------>  0x00b0fff0     1001
    pd      0xff00100c     0x00b0fff4 ------>  0x00b0fff4     10000001.0            

The objects nights, pt, and pd all have auto storage duration. On most implementations, this means they are allocated from the runtime stack. The object nights lives at address 0xff0010001 and stores the value 1001. The object pt lives at address 0xff0010004 and stores the address of a dynamic object created by new, which is 0x00b0fff0. The object pd lives at address 0xff00100c and stores the address of another dynamic object created by new, which is 0x00b0fff4.

The heap objects at addresses 0x00b0fff0 and 0x00b0fff4 store the values 1001 and 10000001.0, respectively.

Edit

FWIW, I wrote a dumper utility some time ago that dumps out object addresses and contents; given the code

#include <cstdio>
#include "dumper.h"

using namespace std;

int main( void )
{
  int nights = 1001;
  int *pt = new int;
  *pt = 1001;
  double *pd = new double;
  *pd = 1000001.0;

  char *names[] = { "nights", "pt", "pd", "*pt", "*pd" };
  void *addrs[] = { &nights, &pt, &pd, pt, pd };
  size_t sizes[] = { sizeof nights, sizeof pt, sizeof pd, sizeof *pt, sizeof *pd };

  dumper( names, addrs, sizes, 5, stdout );

  return 0;
}

I get the output

       Item         Address   00   01   02   03
       ----         -------   --   --   --   --
     nights  0x7fff9efe7c6c   e9   03   00   00    ....

         pt  0x7fff9efe7c60   10   20   50   00    ..P.
             0x7fff9efe7c64   00   00   00   00    ....

         pd  0x7fff9efe7c58   30   20   50   00    0.P.
             0x7fff9efe7c5c   00   00   00   00    ....

        *pt        0x502010   e9   03   00   00    ....

        *pd        0x502030   00   00   00   00    ....
                   0x502034   82   84   2e   41    ...A

In this case, the addresses are real. On my system (x86_64/Linux SLES-10), stack addresses start high and grow "downwards" (towards lower addresses), while heap addresses start low and grow "upwards" (towards higher addresses).

x86 is little endian, meaning the addressed byte is the least significant byte; multi-byte objects need to be read from right to left.


  1. All addresses are made up out of thin air and are not meant to represent any real-world implementation or architecture.