据我所知,变量' q'函数fun()结束后,地址超出范围。那么,为什么代码的输出是" 20 10" ?
int *p2;
void fun(int *ptr)
{
int q=10;
ptr=&q;
p2 = ptr;
}
int main()
{
int r=20;
int *p = &r;
fun(p);
printf("%d %d",*p,*p2);
return 0;
}
答案 0 :(得分:3)
正如其他人所提到的那样,保存局部变量的地址然后在函数返回后尝试取消引用该地址是undefined behavior。
这意味着您的程序可能会崩溃,它可能会出现奇怪的行为,或者它似乎可以正常工作。对于相同的代码或存在看似无关的更改,此行为不需要从一个编译器到下一个编译器保持一致。
话虽这么说,许多编译器通常不会修改函数返回后使用的堆栈部分。它通常不需要额外的工作。所以在fun
返回后立即,它所包含的局部变量仍包含旧值。
在调用printf时,在调用printf之前取消引用指针p2
。由于在此之前没有调用其他函数,因此最后一次调用fun
的a值尚未被覆盖。所以你读了旧值。
如果你在调用printf
之前调用其他函数,之前被q占用的内存位置将被覆盖,这样你就可能会看到其他一些值。
但重申一下,这是未定义的行为。并非所有编译器都需要以这种方式运行。例如,在高安全性环境中,编译器可能会在函数返回后清除堆栈内存,以便无法恢复该函数使用的敏感数据。
答案 1 :(得分:0)
这是纯粹的undefined behavior。
访问无效的内存会调用UB。 (只是因为你可以编写代码)你不应该这样做。
20 10
很可能被认为是垃圾,因为一旦你调用UB,就无法以任何方式证明输出。
FWIW,问题在于通过说p2
来访问*p2
,解除引用p1
就好了,因为C参数是使用pass-by-value传递的,所以对函数内的ptr
不会影响调用者中的实际变量ptr
(不是*ptr
)。
答案 2 :(得分:0)
这是最糟糕的未定义行为。代码似乎正常工作。并且在所有测试和QA期间继续这样做。然后在最繁忙时期的午夜与最重要的客户停止工作。
其他人说UB = UB,UB包括显然正在工作
答案 3 :(得分:0)
正如其他人所说,你有未定义的行为,所以输出可以是任何东西。
然而,除了未定义的行为,你还有一个值得关注的错误。
重写代码以避免UB可能是:
DataGridView
此代码正常,输出为void fun(int *ptr){
int q=10;
ptr=&q;
}
int main(){
int r=20;
int *p = &r;
fun(p);
printf("%d",*p);
return 0;
}
。关键是指针20
按值传递。因此,当函数返回时,函数内部所做的任何更改都将丢失。换句话说,main中的p
未更改,仍指向p
。
如果要更改函数中的指针值,请将其作为双指针传递。与r
一样,将其称为void fun(int **ptr)
并将其称为*ptr = ...