为什么输出" 20 10"而不是垃圾值(悬空指针)?

时间:2016-10-31 18:00:27

标签: c pointers scope undefined-behavior

据我所知,变量' 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;
}

4 个答案:

答案 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 = ...