作者在用C ++解释堆栈和堆时是错误的还是我误读了什么?

时间:2017-06-08 07:58:31

标签: c++ c++11

以下是代码:

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;
}

以下是作者关于代码的说明:

  

需要注意的另一点是, new 通常使用与我们一直使用的普通变量定义不同的内存块。变量 night pd 都将其值存储在称为堆栈的内存区域中,而由 new <分配的内存/ strong>位于名为堆或免费商店的区域。

初步问题:

现在我担心的是:变量 pd 是由关键字 new 创建的,所以它应该存储在名为 heap 的区域中就像变量 pt 一样,因为它们都是由关键字 new 创建的。

我在这里遗漏了什么吗?非常感谢您的投入。

基于保留的修订问题/跟进:

  

这个问题已被5人暂停,因为他们无法理解我在问什么。我相信我的问题已经得到了解答,但对于那些仍然不确定我最初要求的人,请继续阅读:

     

我不清楚作者关于变量及其值存储在内存中的位置的解释。至于作者的解释,我相信通过使用关键字 new 动态创建的任何内存(或者我应该在编译后的运行时说)都存储在堆栈

     

所以,当他写下变量 pd 具有价值时,我感到很困惑   存储在堆栈中,但如果变量又如何可能   是在&#34;运行时&#34;使用关键字 new ,所以它应该是   在中,而不是堆栈

请尝试在您的答案中使用上面的代码作为参考,特别是**变量(night,pd和pt ),以便我可以从该代码中理解它&#39;的观点。

提前谢谢!

5 个答案:

答案 0 :(得分:97)

指针变量ptpd存储在堆栈中。他们指向的值(用new分配)存储在堆上。

如果我写一个带有标有&#34;湖&#34;的箭头的标志,它并不意味着标志本身就是一个湖泊,也不是说它必须安装在湖中。相反,它应该安装在坚实的地面上,指向湖的方向。

答案 1 :(得分:18)

作者唯一的错误是

  1. 一旦完成指针的使用,就不会调用delete

  2. 重复使用endl是值得怀疑的。请改用\n

  3. using namespace std;虽然在教程中经常用来实现简洁,但在生产代码中却是不明智的,特别是在标题中。

  4. 使用int * pt = new int; *pt = 1001;代替int* pt = new int(1001);是有问题的,因为作者拥有它,*pt在两个语句之间处于不必要的未初始化状态。这使得您的代码容易受到不稳定性的影响。

  5. (次要)。如果分配失败,您应始终考虑 new可能抛出std::bad_alloc异常的可能性。

  6. 我不会太担心 stack heap 这两个词;它们是语言实现概念语言本身的一部分。首选术语自动动态存储持续时间。这就是C ++标准所使用的,那么为什么要发明一整套替代术语呢?

    我真的烧掉了这本书并获得了Stroustrup的副本。

答案 2 :(得分:16)

  

现在我担心的是:变量pd是由关键字new创建的,因此它应该像变量pt一样存储在名为heap的区域中,因为它们都是由关键字new创建的。

不,事实并非如此。代码是:

 double * pd = new double; // allocate space for a double

这与以下内容没有什么不同:

double * pd;
pd = new double;

很明显,pd本身不是由new运算符创建的,只是它所拥有的值。但他谈的是pd,而不是它的价值。

答案 3 :(得分:16)

图片会有所帮助。

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            

对象nightsptpd都有auto个存储时长。在大多数实现中,这意味着它们是从运行时堆栈中分配的。对象nights位于地址0xff001000 1 并存储值1001。对象pt位于地址0xff0010004,并存储由new创建的动态对象的地址,即0x00b0fff0。对象pd位于地址0xff00100c,并存储new创建的另一个动态对象的地址,即0x00b0fff4

地址0x00b0fff00x00b0fff4的堆对象分别存储值100110000001.0

修改

FWIW,我前段时间写了一个dumper实用程序来转储对象地址和内容;给出代码

#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;
}

我得到了输出

       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

在这种情况下,地址 是真实的。在我的系统(x86_64 / Linux SLES-10)上,堆栈地址从高处开始并向下增长&#34;向下&#34; (朝向较低的地址),而堆地址开始低并且增长&#34;向上&#34; (朝向更高的地址)。

x86是小端,意味着被寻址的字节是最小有效字节;需要从右到左读取多字节对象。

<小时/>

  1. 所有地址都是凭空创建的,并不代表任何实际的实现或架构。

答案 4 :(得分:7)

pd变量存储在堆栈内存中,但pd指向的内存位置在堆内存中分配。我想作者想要强调这些概念之间的这种差异。