将指针作为参数传递给函数

时间:2012-07-14 01:56:50

标签: c++ pointers

考虑以下示例

class Foo{
  public:
    Foo(int i):x(i){}
    int x;
};

void
bar(Foo *p2)
{
  delete p2; 
  p2 = new Foo(2); 
}  

int
main()
{
  Foo *p1 = new Foo(1);
  cout<<p1->x;
  bar(p1);
  cout<<p1->x;
}

据我所知,指针变量存储在堆栈中,并包含一个地址,指向堆栈中“指向”的动态分配的内存。现在,当我传递指向函数的指针时,在堆栈上创建第二个指针,指向与第一个指针相同的内存地址。当我在bar()中删除p2并分配新内存时,p1和p2应该指向不同的地址,对吗?

但是,如果我编译这段代码,我得到1和2作为输出。这是因为p2设法分配了p1已经指向的相同内存单元,还是我错过了什么?

2 个答案:

答案 0 :(得分:1)

  

这是因为p2设法分配了p1已经指向的相同内存单元格,还是我错过了什么?

你什么都没错过。您已正确识别此程序的行为未定义。根据定义,它可以打印任何内容,包括2

在你的跑步中,只有巧合(很可能,你确定的巧合)导致它打印2。您可以通过在new int(47)之后和现有delete之前添加new来破坏这种巧合。

如果您希望程序按照它的方式运行,但通过已定义的行为,您可以对bar的定义进行小的更改:

void
bar(Foo*& p2)

这会通过引用而不是按值传递参数。通过执行此操作,p2内变量bar的更改将反映在`main p1内。

答案 1 :(得分:0)

除了你的示例之外,指针变量不一定在堆栈上,它们引用的地址不一定在堆上,(但new和malloc都返回堆上的地址)。指针变量和它引用的地址都可以在堆栈,堆,全局/静态变量区域甚至ROM上。你的解释的其余部分是正确的,但你观察到的行为是不确定的,期望它可以重现是非常危险的。任何更改,不同的运行时版本,多线程情况,在不同体系结构上编译或使用其他编译器都可以完全更改结果:随机值或崩溃。