4

这是我的代码:

#include <stdio.h>
//returning a pointer
int *fun()
{
    int i = 10;
    //printf ("%u\n",i);
    //printf ("%u\n",&i);
    return &i;
}
int main()
{
    int *p;
    p = fun();
    printf ("p = %u\n", p);
    printf ("i = %u \n",*p);
    return 0;
}

如果我删除函数 fun 中的注释,那么 main 中的第二个 printf 会显示 10 作为输出。否则它显示一个垃圾值。任何想法?

4

3 回答 3

3

没有注释的行i永远不会被使用。因此,根据您的优化器,i甚至可能永远不会被分配。当您printf在函数中添加时,现在使用该变量,以便编译器i在堆栈帧上分配内存(恰好在您的第二组 printfs 发生时尚未回收)。当然,您不能依赖于何时回收该内存 - 但发生的下一个函数调用很可能会覆盖fun()堆栈帧。

如果您将编译器设置为禁用代码优化,您可能会得到不同的结果。或者您可以尝试将变量设置为volatile告诉编译器它不知道该变量的所有用途,因此即使优化器说不需要它也要分配它(这不会阻止您的变量的内存在您之后被释放离开该功能,它只会首先强制分配)。

作为旁注,这个问题可能出现在嵌入式系统中,您有一个指向硬件寄存器的指针,该寄存器在设置时会触发硬件操作(例如,您可能有控制机器人手臂运动的硬件寄存器)。如果您不声明指向该寄存器的指针,volatile那么编译器可能会优化您的分配,认为它从未使用过。

于 2013-10-14T21:24:48.980 回答
0

fun返回时,超出i范围,因此您返回的地址现在指向其他内容。尝试malloc()一些记忆并返回它。完成后不要忘记打电话free():)

节目中的第二个printf也是纯粹的运气,因为您尚未将该空间/地址用于其他用途。main10

于 2013-10-14T21:05:14.623 回答
0

正如@clcto 在第一条评论中提到的那样,该变量i是函数的本地变量,并且在函数返回时被取消分配。

现在为什么取消注释print函数中的两个语句fun()会使 p 的值为 10?
这可能是由于许多原因,这些原因可能取决于C您的系统的内部行为。但我的猜测是,它的发生是因为打印是如何工作的。
它维护一个我知道的缓冲区。它填充它,然后在完全填充时将其打印到控制台。所以 fun() 中的前两个 print 调用将 i 推送到尚未完全填充的缓冲区。因此,当您从 fun() 返回时,可能会i因为缓冲区正在使用它而没有被取消分配(或者可能是我不确定但由于缓冲区i被保留的任何其他原因。)

为了支持我的猜测,我尝试在再次打印之前刷新缓冲区,现在它不打印 10。您可以在此处看到输出,修改后的代码如下:

#include <stdio.h>
//returning a pointer
int *fun()
{
    int i = 10;
    printf ("%u\n",i);
    printf ("%u\n",&i);
    return &i;
}
int main()
{
    int *p;
    p = fun();
    fflush(stdout);
    printf ("p = %u\n", p);
    printf ("i = %u \n",*p);
    return 0;
}

正如@KayakDave 指出的那样,我认为我的猜测是错误的。它完全适合这种情况。请参考他的答案以获得正确的解释。

于 2013-10-14T21:27:21.947 回答