传递一个指针作为参数传递给函数
问题描述:
请看下面的例子传递一个指针作为参数传递给函数
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已经指向的相同的存储单元,还是有我错过的东西?
答
这是因为p2设法分配与p1已经指向的存储单元相同的存储单元,还是有我遗漏的某些内容?
你没有遗漏任何东西。您已经正确识别出该程序的行为是undefined。根据定义,它可以打印任何东西,包括2
。
在你的跑步中,它只是巧合(很可能是你识别的巧合),导致它打印2
。您可能会在delete
之后和现有new
之前添加new int(47)
,从而中断该巧合链。
如果你的愿望是该程序的行为它的方式,而是通过定义行为,你可以让这个小改动bar
的定义:
void
bar(Foo*& p2)
这一引用传递参数而不是的价值。通过这样做,对bar
内变量p2
的更改反映在p1
内部的main中。
答
除了你的示例中,指针变量不一定在堆栈上,它们引用的地址不一定在堆上(但new和malloc都返回堆中的地址)。指针变量和它引用的地址都可以在堆栈,堆,全局/静态变量区域,甚至ROM中。其余的解释是正确的,但你观察到的行为是不确定的,期望它是可重复的,这确实是非常危险的。任何更改,不同的运行时版本,多线程情况,不同体系结构或其他编译器的编译都可以完全改变结果:随机值或崩溃。
修复这个错误,这个谜将消失。 – 2012-07-14 02:09:31