【问题标题】:Dangling Pointer in CC中的悬空指针
【发布时间】:2011-07-14 10:13:04
【问题描述】:

我用 C 语言编写了一个带有悬空指针的程序。

#include<stdio.h>

int *func(void)
{
    int num;
    num = 100;
    return &num;
}

int func1(void)
{
    int x,y,z;
    scanf("%d %d",&y,&z);
    x=y+z;
    return x;
}

int main(void)
{
    int *a = func();
    int b;
    b = func1();
    printf("%d\n",*a);
    return 0;
}

即使指针悬空,我也得到 输出为 100

我对上述函数func1() 做了一个更改。而不是像上面的程序那样从标准输入中获取yz 的值,现在我在编译时分配值。

我重新定义了func1(),如下:

int func1(void)
{
    int x,y,z;
    y=100;
    z=100;
    x=y+z;
    return x;
}

现在输出为 200

有人可以解释一下上述两个输出的原因吗?

【问题讨论】:

  • 有一个代码按钮可以用来制作整个部分的代码,而不是对每一行使用代码 sn-ps。
  • 对于第一个版本,哪些输入会产生 100 的结果?

标签: c pointers dangling-pointer


【解决方案1】:

请从基本的C学习函数。你的概念有缺陷...main应该是

int main(void)  
{  
    int *a = func();  
    int b;

    b = func1();  
    printf("%d\n%d",*a,func1());  
    return 0;  
}

这将输出100 200

【讨论】:

    【解决方案2】:

    未定义行为表示任何事情都可能发生,包括它会按照您的预期进行。在这种情况下,您的堆栈变量没有被覆盖。

    void func3() {
      int a=0, b=1, c=2;
    }
    

    如果您在func1printf 之间包含对func3() 的调用,您将得到不同的结果。

    编辑:一些平台上实际发生的事情。

    int *func(void)
    {  
        int num;  
        num = 100;  
        return &num;  
    }
    

    为简单起见,假设在调用此函数之前堆栈指针为 10,并且堆栈向上增长。

    当您调用该函数时,返回地址被压入堆栈(位置 10),堆栈指针递增到 14(是的,非常简化)。然后变量 num 在堆栈的 14 位置创建,堆栈指针递增到 18。

    返回时,返回指向地址 14 的指针 - 返回地址从堆栈中弹出,堆栈指针返回到 10。

    void func2() {
        int y = 1;
    }
    

    在这里,同样的事情发生了。返回地址推入位置,y 在位置 14 创建,将 1 分配给 y(写入地址 14),返回并将堆栈指针返回到位置 10。

    现在,您从func 返回的旧int * 指向地址14,对该地址的最后修改是func2 的局部变量赋值。因此,您有一个悬空指针(堆栈中位置 10 以上的任何内容均无效),它指向调用 func2 时的剩余值

    【讨论】:

    • 当我使用scanf()时,为什么答案是num的值。堆栈变量 num 是否不被 y 或 z 覆盖。你能解释一下哪些变量会进入堆栈吗?
    • 编译器可以免费检查您的应用程序并计算“这些调用需要 X 字节的堆栈总数”,一次性将所有这些都放在一边,因此您可以获得不同的本地地址这些函数调用中的变量。这是未定义的行为 - 您需要反汇编可执行文件以查看到底发生了什么
    • 非常感谢 Erik 的详细解释。
    【解决方案3】:

    这是因为内存分配的方式。

    在调用func 并返回一个悬空指针之后,存储num 的堆栈部分仍然具有值100(这就是您之后看到的)。我们可以根据观察到的行为得出这个结论。

    更改之后,看起来发生的情况是func1 调用用func1 内部的加法结果覆盖了a 指向的内存位置(之前用于func 的堆栈空间是现在被 func1 重用),这就是为什么你会看到 200。

    当然,所有这些都是未定义的行为,所以虽然这可能是一个很好的哲学问题,但回答它并不能真正给你带来任何好处。

    【讨论】:

      【解决方案4】:

      返回指向局部变量的指针会产生未定义的行为,这意味着程序所做的任何事情(任何事情)都是有效的。如果你得到了预期的结果,那只是运气不好。

      【讨论】:

        【解决方案5】:

        使用悬空指针,程序的结果是不确定的。这取决于堆栈和寄存器的使用方式。使用不同的编译器、不同的编译器版本和不同的优化设置,你会得到不同的行为。

        【讨论】:

          【解决方案6】:

          这是未定义的行为。它现在可以在您的计算机上正常工作,从现在起 20 分钟,可能在一小时后崩溃,等等。一旦另一个对象在堆栈中与 num 相同的位置,您将注定

          【讨论】:

            【解决方案7】:

            悬空指针(指向已解除关联的位置的指针)会导致未定义行为,即任何事情都可能发生。

            特别是,内存位置func1 中被机会* 重用。结果取决于堆栈布局、编译器优化、架构、调用约定和堆栈安全机制。

            【讨论】:

              猜你喜欢
              • 2021-09-14
              • 1970-01-01
              • 1970-01-01
              • 2013-01-10
              • 1970-01-01
              • 2019-06-18
              • 1970-01-01
              • 2020-09-07
              相关资源
              最近更新 更多