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
Not calling
delete
once use of the pointers is finished.The repeated use of
endl
is questionable. Use\n
instead.using namespace std;
, whilst often used in tutorials to achieve brevity is ill-advised in production code, particularly in headers.Using
int * pt = new int; *pt = 1001;
in place ofint* 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.(Minor). You should always think about the possibility that
new
can throw astd::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 0xff001000
1 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.
- All addresses are made up out of thin air and are not meant to represent any real-world implementation or architecture.