【问题标题】:Using pointer as return value in function in c [duplicate]在c中的函数中使用指针作为返回值[重复]
【发布时间】:2013-10-14 20:58:24
【问题描述】:

这是我的代码:

#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 中的 cmets,那么 main 中的第二个 printf 会显示 10 作为输出。否则它显示一个垃圾值。有什么想法吗?

【问题讨论】:

  • 而你想知道的是什么? i 位于堆栈上,因此当函数返回 &amp;i 时,i 的内存位置无效。我想你想说:int* i = malloc( sizeof( int ) ); *i = 10; return i;
  • 同样在你的 printf 格式字符串中,你传递了 %u,这意味着无符号,但给它一个 int,它是有符号的——将导致未定义的行为。
  • 我明白为什么 *p 显示垃圾值,我不明白为什么在函数 fun 中取消注释 printfs 会导致 main 中的第二个 printf 打印正确的输出 10..!
  • 或者声明为static int i = 10;
  • 返回本地地址会导致未定义的行为。未定义的行为意味着编译器可以为所欲为。如果你有一个非常邪恶的编译器,那么你的代码可以运行多年,然后在半夜在你最大的客户那里失败

标签: c pointers


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

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

    而且main 中的第二个printf 显示10 纯属幸运,因为您尚未将该空间/地址用于其他用途。

    【讨论】:

      【解决方案3】:

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

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

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

      #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 指出的那样。它完全适合这种情况。正确解释请参考his answer

      【讨论】:

      • flush() 调用创建了一个新的堆栈帧,它覆盖了 fun() 使用的堆栈帧。这可能就是我停止打印的原因。
      • 是的,谢谢!!指出来。
      猜你喜欢
      • 2018-03-23
      • 1970-01-01
      • 2016-03-25
      • 1970-01-01
      • 2016-07-24
      • 2014-08-16
      • 2018-03-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多