【问题标题】:Understanding these Pointer Statements - Diagram理解这些指针语句 - 图表
【发布时间】:2012-10-21 03:47:18
【问题描述】:

我试图理解以下 3 个涉及指针的代码语句(通过图像图表)。如果您可以在没有图像的情况下解释它也可以使用

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

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

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

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

【问题讨论】:

  • #2 - 它指向一个地址,但可以安全地移动到下一个地址。
  • 什么意思,能不能详细解释一下
  • 这意味着你可以像一个由两个整数组成的数组一样索引它,它最初会指向第一个元素。
  • #2 - 它创建了一个2 * sizeof(myobj) 的连续空间,并且指针*ptrb 指向该空间的最低地址。第二个元素可以通过ptrb[1] 访问。我不确定*(ptrb + sizeof(myobj)) 是否可以完成这项工作。
  • @Alvin:指针算法考虑了指向的类型的大小——所以ptrb[1]在这种情况下等同于*(ptrb + 1)。您的其余评论是正确的,+1。

标签: c++ pointers


【解决方案1】:

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

让我们从一个简单的案例开始,把操作符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”分配三个不同的东西:

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

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

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

就这么简单!

【讨论】:

  • 很好的解释!谢谢你的努力!而且,您介意说一下您用来绘制图表的内容吗?
  • @Meysam:谢谢。这些图表是使用 Omni Graff (omnigroup.com/products/omnigraffle) 制作的。
  • 嗨,好帖子 - 你输入了 printf("pointer size: %lu\n", sizeof(void *));是不是少了什么?
  • @VladLazarenko 你也可以用图表解释一下myobj *ptrb = new myobj[2]();,在这种情况下,ptrb 会指向一个地址还是多个地址?
  • 回答了这个问题。感谢您的精彩解释
猜你喜欢
  • 2015-01-28
  • 2017-11-12
  • 2016-02-19
  • 1970-01-01
  • 1970-01-01
  • 2011-01-18
  • 1970-01-01
  • 1970-01-01
  • 2013-08-03
相关资源
最近更新 更多