理解这些指针语句 - 图表

时间:2012-10-21 03:47:18

标签: c++ pointers

我试图理解以下3个涉及指针的代码语句(通过图像图表)。如果你可以解释它没有图像也可以工作

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

以下是我的理解,如果我错了,请纠正我。此外,图像中的地址完全是虚构的(我知道它们没有意义)。我对理解的主要关注基本上是陈述2和陈述3.

声明1: ptra(堆栈上的某个地址)指向堆上的地址

声明2: ptra(堆栈中的某个地址)指向一个有2个部分的地址?那是对的吗 ?

enter image description here

1 个答案:

答案 0 :(得分: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

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

simple data layout

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

当涉及动态分配时,图片会有所改变。例如,当运算符“new”用于分配这样的对象时:

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

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

dynamic memory layout

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

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

内存布局可能如下所示:

with pointer to pointer(s)

顺便说一下,你的第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;
}

它将创建以下布局:

enter image description here

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

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

然后,用“new”分配三个不同的东西:

  1. 类型myobj的两个对象分配有表达式new myobj[2](),第一个对象的地址存储在指针ptra中。
  2. 类型myobj的四个对象分配有表达式new myobj[4](),该表达式的结果是四个对象中第一个的地址,并存储在指针“ptrb”中。
  3. 使用表达式new myobj*[2]分配两个指针。该表达式的结果是两个指针中的第一个的地址。该地址存储在变量ptrc
  4. 现在,这两个分配的指针(在“Block C”中)指向“无处”。因此,仅仅为了示例,我们使它们指向与ptra相同的对象,并且ptrb通过“按值”复制指针来指向:

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

    那很简单!