【问题标题】:Does printf function affect the life of variable?printf 函数会影响变量的寿命吗?
【发布时间】:2014-08-12 15:51:12
【问题描述】:

这是我的简单 C 程序。

#include <stdio.h>
float*multiply(int, float);

main(){
   int i =3;
   float f = 3.50, *p;
   p = multiply(i, f);
   printf("%u\n", p);
   printf("%f\n", *p);
   return 0;
}

float *multiply(int ii, float ff){
   float product = ii * ff;
   printf("%f\n", product);
   printf("%u\n", &product);
   return (&product);
}

这个程序给出以下输出:-

但是,当我注释掉multiply 函数中的两个“printf”语句时,它会给出以下输出:-

我真的很确定我没有犯任何愚蠢的错误。我只是注释掉两行。 谁能告诉我为什么会这样?这是操作系统/系统相关的问题吗? printf函数如何增加变量的寿命?

【问题讨论】:

  • 未定义的行为是未定义的。取消引用悬空指针是未定义的行为。使用%u 打印指针也是如此。那应该是%p(void *)p
  • 永远不要返回指向本地的指针...
  • 如果你想在函数内外使用相同的内存区域,你应该将它作为参考传递给函数。像 void/bool multiply(int ii, float ff, float &result);
  • 您也可以malloc()浮动指针,然后将计算结果存储在其中。不要忘记在 main 中 free()

标签: c pointers printf


【解决方案1】:

您正在返回基于堆栈的本地变量product 的地址,这将导致未定义的行为。

另外,要打印指针的值,您应该使用%p 而不是%uhttp://www.cplusplus.com/reference/cstdio/printf/

【讨论】:

    【解决方案2】:

    这只是一个未定义的行为。变量的生命周期保持不变 - 它仅限于函数运行的时间。一旦功能退出,所有赌注都将取消。调用printf 会更改堆栈的状态,因此您看到的结果会有所不同。但是,在这两种情况下,结果都是未定义的,这意味着您的程序可以打印任何内容,甚至崩溃。

    您可以通过在valgrind 中运行您的程序来检测这种未定义的行为。

    注意:打印指针的正确方法是printf("%p\n", (void*)&amp;product);

    【讨论】:

      【解决方案3】:

      如其他答案中所述,通过返回局部变量product 的地址,您的结果是未定义的。但是,如果您改为返回 product 的值,则结果定义明确,您的程序将按预期运行:

      #include <stdio.h>
      
      float multiply(int ii, float ff){
          float product = ii * ff;
          return product;
      }
      
      int main(void){
          int i =3;
          float f = 3.50, p;
          p = multiply(i, f);
          printf("%p\n", &p);
          printf("%f\n", p);
          return 0;
      }
      

      0x7fff521cfac0
      10.500000

      【讨论】:

        【解决方案4】:

        如果您使用标志 -Wall 编译它,您将看到以下警告:

        test.c:19:4: warning: function returns address of local variable [-Wreturn-local-addr]
        

        这是因为您返回了product 的内存地址,并将float p 设置为指向该地址,但是由于该函数已经完成了它使用的内存从堆栈中弹出并且不再保证在那里,意思是p可以指向垃圾。

        【讨论】:

          【解决方案5】:

          在 printf() 和 scanf() 之后,有时您需要执行 fflush(stdin) 或 flushall()。试试那个。

          【讨论】:

          • "需要做 fflush(stdin)"?您的参考资料是什么?
          • 不知道为什么我们需要它,但我曾经使用它来解决 scanf("%c") 的问题
          【解决方案6】:

          函数中局部变量的地址取决于调用函数时执行点的堆栈状态(SP 寄存器的值)。

          也就是说,这个地址不一定每次函数调用都一样。

          因此,返回局部变量的地址会导致未定义的行为。


          您可以观察以下程序的输出作为示例:

          int func1()
          {
              int var = 1;
              printf("%p\n",&var);
              return var;
          }
          
          int func2()
          {
              int var = 2;
              func1();
              return var;
          }
          
          int main()
          {
              func1(); // main --> func1
              func2(); // main --> func2 --> func1
              return 0;
          }
          

          正如@chux 在下面的其中一个 cmets 中所暗示的那样,C 语言标准并未规定应如何在内存中分配变量。所以上面描述的问题是大多数编译器如何在内存中分配本地变量的结果。

          【讨论】:

          • 注意:某些体系结构存在,因此“函数中局部变量的地址取决于堆栈的状态”是不正确的。即:“函数中局部变量的地址是固定的”。不过,对于 C,OP 的代码是 UB。
          • @chux:我同意 C 语言标准没有定义变量在内存中分配的方式这一事实。然而,给出一个“大概”实用和建设性的答案感觉有点尴尬,这只不过是说 - “这是标准未定义的行为”。为什么它是未定义的行为?好吧,因为编译器如何实现标准。该标准是否说明了编译器应如何实现它?不......我希望你在这一点上明白我的意思:)我在这个网站上看到了很多“UB”的答案,根本没有“达到目的”......
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-03-17
          • 1970-01-01
          • 1970-01-01
          • 2011-05-21
          相关资源
          最近更新 更多