#include<iostream.h>
#include<conio.h>
int *p;
void Set()
{
int i;
i=7;
p=&i;
}
int Use()
{
double d;
d=3.0;
d+=*p;
//if i replace the above 3 statements with --> double d=3.0+*p; then output is 10 otherwise the output is some random value(address of random memory location)
//why is this happening? Isn't it the same?
return d;
}
void main()
{
clrscr();
Set();
cout<<Use();
getch();
}
我的问题如上面的评论所述。我想知道输出差异的确切原因。在上面的代码输出中是随机内存位置的一些地址,我知道这是因为 i 是 Set(( 的局部变量,但在第二种情况下它是如何可见的,即用双 d=3.0+*p 替换它;因为这样输出是 10( 7+3 ( 虽然 7 不应该可见?
使用指针 p
的结果是未定义的,它也可能给你一个段错误或只返回 42。您获得的结果背后的技术原因可能是:
-
Set
内的i
放在堆栈上。值 7 ist 存储在那里,p
指向内存中的该位置。当你从Set
返回时,值保留在内存中:堆栈没有被"销毁",它只是重置了堆栈指针。p
仍然指向此位置,该位置仍包含"3"的整数表示形式。 -
在
Use
内部,堆栈上的相同位置被重用于d
。 -
当编译器没有优化时,在第一种情况下(即一行中的整个计算(,它首先使用值 7(它仍然存在于内存中,
p
指向它(,进行计算,覆盖该值(因为您将其分配给位于同一位置d
(并返回它。 -
在第二种情况下,它首先用双精度值 3.0 覆盖该值,然后将前 4 个字节解释为整数值以计算
d+=*p
中的*p
。
这个案例说明了为什么返回对局部变量的指针/引用是如此糟糕:在编写函数Set
时,您甚至可以编写某种单元测试,但它们不会检测到错误。它可能会被忽视,直到软件投入生产,并且必须执行一些非常关键的任务,然后就会失败。
这适用于所有类型的"未定义行为",特别是在C/C++等"低级"语言中。不好的是,"未定义"很可能意味着"完美地工作,直到为时已晚"......
退出函数后 设置指针 p 的值由于破坏局部变量 i 而变得无效。程序具有未定义的行为。