可能重复:
Can a local variable's memory be accessed outside its scope?
今天我参加了一个关于基本C编码的研讨会,我们偶然发现了一个脑力激荡器,现在的助手都没有能够回答我的内容。
代码是:
#include <studio.h>
int *f(int a) {
int b = 2 * a;
return &b;
}
int main(void) {
int *p4;
int *p8;
p4 = f(4);
p8 = f(8);
printf("p4: %i / p8: %i\n", *p4, *p8);
}
我知道代码有什么问题,我自己也不会编写类似的东西,但它仍然很有趣。
输出是:
p4:16 / p8:16
当然是
p4:8 / p8:16
我最初的预期是我们会收到一个错误,因为在通过&b
的功能f之后不再存在(变量范围)。
我认为id在这里发布,看看是否有人有更好的解释。
IMPORTANT:
这不是一个如何在函数中添加2个int的问题 - 我完全有能力 - 它:为什么在为printf检索它时将数字16存储在* p4。
期待鼓舞人心的答案, 塞巴斯蒂安
答案 0 :(得分:5)
为检索printf时,为什么数字16存储在* p4。
未定义的行为 - 任何事情都可能发生。
int *f(int a) {
int b = 2 * a;
return &b;
}
您正在返回一个指向已销毁变量的指针,然后您将访问该内存位置。那就是UB。
答案 1 :(得分:2)
此行包含多个未定义行为案例:
*p4 = *(f(4));
第一个问题是在右侧,正如您所指出的那样f
返回一个指向自动变量的指针。使用该指针是一个错误,正如您所知,在这种情况下和测试中,未定义的行为不会显示为崩溃,而是访问内存(即堆栈中的某个位置)。
第二个问题是左手边。指针p4
从未初始化,这意味着您还在表达式*p4
中导致未定义的行为,由于某种原因导致应用程序崩溃。但不知道p4
的价值是什么,没有进一步的分析是可能的。即它可以指向内存中的任何位置,无论是否有效,并且后面的任何操作都可能正在更改该地址的值,因此您不能指望任何位置。
修改后:
p4 = f(4);
p8 = f(8);
这仍然是未定义的行为,但对行为的简单解释(即使它是常见的,你不能依赖)是变量b
在两次调用中都位于内存中的同一地址f
。这可以通过打印指针(而不是指向的值)轻松测试。对于如何/为何发生这种情况的解释是第一个f
调用的堆栈帧被重用于第二个,并且因为函数完全相同,所有内部变量的位置是相同的 for连续2次通话