C中的悬空指针

时间:2011-03-13 11:17:17

标签: c pointers dangling-pointer

我用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

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

7 个答案:

答案 0 :(得分:16)

未定义的行为意味着任何事情都可能发生,包括它会像您期望的那样。在这种情况下,您的堆栈变量不会被覆盖。

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

如果您在func3()func1之间加入printf来电,则会得到不同的结果。

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

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

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

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

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

void func2() {
    int y = 1;
}

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

现在,从int *返回的旧func指向地址14,对该地址的最后修改是func2的本地变量赋值。所以,你有一个悬空指针(堆栈中位置10以上没有任何内容有效)指向调用func2

的剩余值

答案 1 :(得分:4)

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

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

在更改之后,看起来会发生的事情是func1调用覆盖了a指向的内存位置以及func1内的添加结果(之前的堆栈空间)用于func的{​​{1}}现在由func1重复使用,这就是为什么你会看到200。

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

答案 2 :(得分:2)

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

答案 3 :(得分:1)

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

特别是,func1中的偶然 *会重复使用内存位置。结果取决于堆栈布局,编译器优化,体系结构,调用约定和堆栈安全机制。

答案 4 :(得分:1)

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

答案 5 :(得分:1)

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

答案 6 :(得分:-1)

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

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

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

这将输出100 200