我试图理解以下3个涉及指针的代码语句(通过图像图表)。如果你可以解释它没有图像也可以工作
1- myobj *ptra = new myobj();
2- myobj *ptrb = new myobj[2]();
3- myobj **ptrc = new *myobj();
以下是我的理解,如果我错了,请纠正我。此外,图像中的地址完全是虚构的(我知道它们没有意义)。我对理解的主要关注基本上是陈述2和陈述3.
声明1: ptra(堆栈上的某个地址)指向堆上的地址
声明2: ptra(堆栈中的某个地址)指向一个有2个部分的地址?那是对的吗 ?
答案 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
这对应于内存中的以下简单布局:
那么你的绘画有什么不同?指针和对象的地址。如果指针本身位于地址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]();
表达式的结果,其中有一个指向动态分配的两个对象的指针。指针本身指向分配的两个中的第一个对象:
还有一次关于指针的指针,以便你可以看到差异。请考虑以下代码:
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;
然后,用“new”分配三个不同的东西:
myobj
的两个对象分配有表达式new myobj[2]()
,第一个对象的地址存储在指针ptra
中。myobj
的四个对象分配有表达式new myobj[4]()
,该表达式的结果是四个对象中第一个的地址,并存储在指针“ptrb”中。new myobj*[2]
分配两个指针。该表达式的结果是两个指针中的第一个的地址。该地址存储在变量ptrc
。现在,这两个分配的指针(在“Block C”中)指向“无处”。因此,仅仅为了示例,我们使它们指向与ptra
相同的对象,并且ptrb
通过“按值”复制指针来指向:
ptrc[0] = ptra;
ptrc[1] = ptrb;
那很简单!