fflush()函数在处理悬空指针方面有什么作用?

3
我发现这个页面,它说明了悬空指针的常见创建方式。
下面的代码用于说明通过返回局部变量的地址来创建悬空指针:
// The pointer pointing to local variable becomes  
// dangling when local variable is static.
#include<stdio.h>

int *fun()
{
    // x is local variable and goes out of scope 
    // after an execution of fun() is over.
    int x = 5;

    return &x;
}

// Driver Code
int main()
{
    int *p = fun();
    fflush(stdout);

    // p points to something which is not valid anymore
    printf("%d", *p);
    return 0;
}

在运行此代码时,我得到了编译器警告(如预期的那样):
 In function 'fun':
12:2: warning: function returns address of local variable [-Wreturn-local-addr]
  return &x;
  ^

这是我得到的输出(目前为止很好):

32743

然而,当我注释掉fflush(stdout)这一行时,我得到的输出结果如下(与同一编译器警告一样):
5

这种行为的原因是什么?fflush命令的存在/不存在如何导致这种行为变化?

1
https://dev59.com/ZWw15IYBdhLWcg3wuuCn#6445794 - Michael Burr
这种行为的原因是什么?这是未定义行为。您使用fflush是无关紧要的。(fflush会清空stdout的内容,但由于您没有缓冲区,它没有任何合法的目的)。您可能会得到5,您可能会得到一个Segmentation Fault,这是未定义的 - David C. Rankin
2个回答

3
返回指向栈上对象的指针是不好的,就像您所提到的那样。您之所以只在 fflush() 调用时看到问题,是因为如果没有该调用,则栈不会被修改。也就是说,5 仍然在原位,因此指针解引用仍将把该值(即5)返回给您。如果在 funprintf 之间调用一个函数(几乎任何函数都可能),它几乎肯定会覆盖该栈位置,从而���后面的解引用返回任何该函数留下的垃圾数据。

printf() 也会放在堆栈上吗?这会导致指针所指向的地址被其他东西(可能)覆盖吗? - Arpith
任何事情都是可能的。然而显然这并不适用于你的情况。 - Carl Norum
我明白了。尝试了一个简单的sleep(1),就解决了问题。感谢@CarlNorum的帮助。 - Arpith

0

这是因为调用fflush(stdout)会写入到x所在的堆栈。

让我解释一下。汇编语言中的堆栈(所有编程语言最终以某种方式运行)通常用于存储局部变量、返回地址和函数参数。当调用函数时,它将这些内容推送到堆栈上:

  • 执行代码后继续执行的地址。
  • 按照调用约定确定顺序的函数参数。
  • 函数使用的局部变量。

然后,这些内容逐个从堆栈中弹出,只需更改CPU认为堆栈顶部的位置即可。这意味着数据仍然存在,但不能保证它会继续存在。

fun()之后调用另一个函数会覆盖堆栈顶部上面的先前值,本例中为stdout的值,因此指针引用的值会发生更改。

如果没有调用另一个函数,则数据仍然存在,并且在解除引用指针时仍然有效。


2
我曾经在一个系统上编写代码,其中堆栈没有用于本地变量和函数参数。 - M.M
如果OP在x86或x86-64系统上编程(大多数个人计算机),则堆栈用于本地变量和函数参数。如果他们在嵌入式系统上编程,则OP最好了解所选择系统的特殊性,并相应地采取行动。无论如何,返回指向本地变量的指针都是未定义的行为。 - user7881131

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接