【问题标题】:Why is the output "20 10" and not Garbage value ( Dangling pointers)?为什么输出“20 10”而不是垃圾值(悬空指针)?
【发布时间】:2017-03-13 20:53:17
【问题描述】:

据我所知,函数 fun() 结束后,变量 'q' 和 is 地址超出范围。那么,为什么代码的输出是“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;
}

【问题讨论】:

  • 因为它是未定义的行为。
  • 如何区分垃圾值和非垃圾值?您的 10 是一个垃圾值,与任何其他垃圾值一样好。
  • 10 是垃圾。
  • 这总是一个有趣的解释:stackoverflow.com/questions/6441218/…
  • 在某些时候,我们可能需要一个规范的 UB Q&A 来进行重复数据删除(比如“浮点数是否损坏?”之一)。由于 OP 依赖于 UB 而出现的 C 问题数量多得离谱,而对其他用户有帮助的却很少。

标签: c pointers scope undefined-behavior


【解决方案1】:

正如其他人所提到的,保存局部变量的地址然后在函数返回后尝试取消引用该地址是undefined behavior

这意味着您的程序可能会崩溃,它可能会表现出奇怪的行为,或者它可能看起来可以正常工作。对于相同的代码或存在看似不相关的更改,此行为不需要从一个编译器到下一个编译器保持一致。

话虽如此,许多编译器通常不会在函数返回后修改函数使用的堆栈部分。这是通常不需要的额外工作。所以在fun 返回之后,它的局部变量仍然包含它们的旧值。

在调用 printf 时,指针 p2 在调用 printf 之前被取消引用。由于在此发生之前没有调用其他函数,因此上次调用 fun 的 a 的值尚未被覆盖。所以你读取旧值。

如果您在调用 printf 之前调用了其他函数,则之前被 q 占用的内存位置将被覆盖,因此您可能会看到其他值。

不过,重申一下,这是未定义的行为。并非所有编译器都必须以这种方式运行。例如,在高安全性环境中,编译器可能会在函数返回后清除堆栈内存,从而无法恢复该函数使用的敏感数据。

【讨论】:

  • 另一方面,在许多嵌入式平台上,函数返回后发生的中断可能会破坏该函数以前使用的堆栈帧;由于中断通常会在不可预知的时间到达,这意味着在大多数情况下,人们无法对以前的堆栈帧的内容说任何有用的信息。
【解决方案2】:

这是最糟糕的未定义行为。该代码似乎可以正常工作。并在所有测试和 QA 期间继续这样做。然后在您最重要的客户最繁忙的午夜,它停止工作。

但是正如其他人所说的那样 UB = UB,UB 包括显然工作

【讨论】:

    【解决方案3】:

    正如其他人所说,你有未定义的行为,所以输出可以是任何东西。

    但是,除了未定义的行为之外,您还有一个值得关注的错误。

    重写代码以避免 UB 可能是:

    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。重点是指针p是按值传递的。因此,当函数返回时,函数内部所做的任何更改都会丢失。也就是说,main 中的p 没有改变,仍然指向r

    如果要更改函数中的指针值,请将其作为双指针传递。像void fun(int **ptr)一样,像*ptr = ...一样调用它并像fun(&p)一样调用函数

    【讨论】:

      【解决方案4】:

      这是纯粹的undefined behavior

      访问无效的内存会调用 UB。 (仅仅因为你会写代码)你不应该这样做。

      20 10 很可能被视为垃圾,因为一旦调用 UB,输出就无法以任何方式证明。

      FWIW,问题在于通过说*p2 访问p2,取消引用p1 就可以了,因为在C 中,参数是使用传值传递的,所以函数内部对ptr 的任何更改不会影响调用者中的实际变量ptr(不是*ptr)。

      【讨论】:

        猜你喜欢
        • 2020-08-29
        • 1970-01-01
        • 2021-12-18
        • 2015-07-03
        • 2019-08-16
        • 2021-11-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多