#include <stdio.h>
int main()
{
int i = 10;
int *p = &i;
foo(&p);
printf("%d ", *p);
printf("%d ", *p);
}
void foo(int **const p)
{
int j = 11;
*p = &j;
printf("%d ", **p);
}
上面的code
打印:
11 11 Undefined-value
为什么第三次打印未定义的值?
为什么最后不打印11
?
答案 0 :(得分:4)
在foo
内,将*p
(与p
中的main
相同)设置为局部变量的地址。当foo
返回时,该变量超出范围,因此该地址不会指向任何有意义的地方。
返回局部变量的地址,然后取消引用该地址将调用undefined behavior。
关于可能发生的情况,当您从*p
返回后第一次读取foo
时,j
驻留在堆栈中的地址还没有由于尚未调用其他函数,因此尚未重用。然后,当您调用printf
时,该地址会在printf
的堆栈框架内重用。然后,下次读取*p
时,它将包含放置在此的最后一个函数调用。
但是,重申一下,这是未定义的行为,因此您不能依赖此情况。使用不同的编译器甚至具有不同优化设置的同一编译器进行编译,都可以更改未定义行为的显示方式。
作为未定义行为的示例,在使用-O0的gcc进行编译时,我得到以下输出:
11 11 11
使用-O1:
11 11 0
带有-O2:
11 0 0
带有-O3:
11 0 0
请注意,在一种情况下,我们会以不同的方式获得“预期的”输出,而在其他情况下,则无法获得。
您可以通过将j
定义为static
或在文件作用域(即函数外部)来避免此问题,在这种情况下,变量的生存期是整个程序的生存期,因此是其地址始终有效。
答案 1 :(得分:1)
尝试一下(不要将int j
定义为局部变量):
#include <stdio.h>
void foo(int **const p);
int j = 11; // define int j outside of the function as public
int main()
{
int i = 10;
int *p = &i;
foo(&p);
printf("%d ", *p);
printf("%d ", *p);
}
void foo(int **const p)
{
*p = &j;
printf("%d ", **p);
}
输出将是:
11 11 11
当您在int j = 11;
中定义void foo(int **const p)
时,这些步骤会变多:
*p
带j
地址**p
将是11
,并且foo
函数将返回现在因为int j;
是本地的,所以j
被调用后foo
将会被破坏!
**p
指向未定义的内容,在这种状态下,您将获得Undefined-value
的输出。