1

我用 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()。现在我在编译时分配值,而不是像上面的程序那样从标准输入中获取y值。z

我重新定义func1()如下:

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

现在输出是 200

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

4

7 回答 7

16

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

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

func3()如果你在两者之间加上一个调用func1printf你会得到不同的结果。

编辑:在某些平台上实际发生了什么。

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。

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

于 2011-03-13T11:20:32.160 回答
4

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

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

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

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

于 2011-03-13T11:24:33.520 回答
2

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

于 2011-03-13T11:22:01.613 回答
1

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

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

于 2011-03-13T11:21:54.697 回答
1

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

于 2011-03-13T11:22:04.150 回答
1

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

于 2011-03-13T11:23:33.250 回答
-1

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

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

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

这将输出100 200

于 2012-06-21T13:35:50.313 回答