3

我试图理解以下 3 个涉及指针的代码语句(通过图像图)。如果您可以在没有图像的情况下对其进行解释,那也可以

1- myobj *ptra = new myobj();
2- myobj *ptrb = new myobj[2]();
3- myobj **ptrc = new *myobj();

以上是我的理解,如有错误请指正。图像中的地址也是完全虚构的(我知道它们没有意义)。我的主要理解问题基本上是陈述2和陈述3。

语句 1:ptra(堆栈上的某个地址)指向堆上的一个地址

语句 2: ptra (堆栈上的某个地址)指向一个包含 2 个部分的地址?那是对的吗 ?

在此处输入图像描述

4

1 回答 1

7

您的理解有些正确,尽管您似乎将太多东西混合在一起并且您的图表缺少细节。以下是我为一些最简单的情况绘制它的方法......

让我们从一个简单的案例开始,将操作员new排除在外:

#include <cstdio>

struct myobj {
    int v;
};

int main()
{
    myobj obj[2];

    obj[0].v = 1;
    obj[1].v = 2;

    myobj *ptra = &obj[0];
    myobj *ptrb = &obj[1];
    myobj **ptrc = &ptrb;

    printf("obj size is: %lu\n", sizeof(myobj));
    printf("pointer size: %lu\n", sizeof(void *));

    printf("obj[0] address: %p\n", (void *)&obj[0]);
    printf("obj[1] address: %p\n", (void *)&obj[1]);
    printf("ptra address is %p, it points to %p\n", (void *)&ptra, (void *)ptra);
    printf("ptrb address is %p, it points to %p\n", (void *)&ptrb, (void *)ptrb);
    printf("ptrc address is %p, it points to %p\n", (void *)&ptrc, (void *)ptrc);
}

上面的程序将输出如下内容:

$ g++ -Wall -pedantic -o test ./test.cpp 
$ ./test 
obj size is: 4
pointer size: 8
obj[0] address: 0x7fff5b73dbc0
obj[1] address: 0x7fff5b73dbc4
ptra address is 0x7fff5b73dbb8, it points to 0x7fff5b73dbc0
ptrb address is 0x7fff5b73dbb0, it points to 0x7fff5b73dbc4
ptrc address is 0x7fff5b73dba8, it points to 0x7fff5b73dbb0

这对应于内存中的以下简单布局:

简单的数据布局

那么和你的画有什么不同呢?指针和对象的地址。如果指针本身放在地址 0,那么下一个指针就不能放在地址 1 上,因为指针本身占用了更多的空间,所以其他数据只能放在0 + sizeof(void*)地址上。对于对象,下一个地址至少要大于对象本身的大小(即sizeof(myobj))。

当涉及到动态分配时,情况会发生一些变化。例如,当使用“new”运算符分配对象时,如下所示:

myobj *ptra = new myobj();
myobj *ptrb = new myobj();
myobj **ptrc = &ptrb;

...您可以想到这样的内存布局:

动态内存布局

现在,指向另一个指针 (**) 的指针只不过是指向一个或多个指向对象的指针中的第一个的指针。容易,对吧?任何您都可以拥有指向指针的指针...无论如何,使用动态分配的指针指针,如下所示:

myobj *ptra = new myobj();
myobj *ptrb = new myobj();
myobj **ptrc = new myobj*[2];
ptrc[0] = ptra;
ptrc[1] = ptrb;

内存布局可能如下所示:

带有指向指针的指针

顺便说一句,您在此处的第 3 行有错误 - myobj **ptrc = new *myobj();。应该是myobj **ptrc = new myobj*();

为了解决您以后的问题,下图描绘了myobj *ptrb = new myobj[2]();表达式的结果,其中您有一个指向动态分配的两个对象的指针。指针本身指向两个已分配对象中的第一个:

myobj *ptrb = new myobj[2]();

还有一次关于指针的指针,以便您可以看到不同之处。考虑以下代码:

struct myobj {
    int v;
};

int main()
{
    myobj *ptra = new myobj[2]();
    myobj *ptrb = new myobj[4]();
    myobj **ptrc = new myobj*[2];

    ptrc[0] = ptra;
    ptrc[1] = ptrb;

    ptrc[0][0].v = 1;
    ptrc[0][1].v = 2;
    ptrc[1][0].v = 3;
    ptrc[1][1].v = 4;
    ptrc[1][2].v = 5;
    ptrc[1][3].v = 6;
}

它将创建以下布局:

在此处输入图像描述

如您所见,堆栈包含三个非动态分配的指针(它们也是对象)。这是声明的结果:

myobj *ptra;
myobj *ptrb;
myobj **ptrc;

然后,三个不同的东西被分配了“新”:

  1. myobj用表达式分配两个类型的对象,new myobj[2]()第一个对象的地址存储在指针中ptra
  2. 四个类型myobj的对象用表达式分配new myobj[4](),该表达式的结果是四个对象中第一个的地址,它存储在指针“ptrb”中。
  3. 使用 with 表达式分配两个指针new myobj*[2]。该表达式的结果是两个指针中第一个的地址。该地址存储在变量中ptrc

现在,这两个分配的指针(在“块 C”中)指向“无处”。因此,为了举例,我们让它们指向相同的对象,ptraptrb通过“按值”复制指针来指向:

ptrc[0] = ptra;
ptrc[1] = ptrb;

就这么简单!

于 2012-10-21T05:20:35.633 回答