【问题标题】:printf changes the value [duplicate]printf 更改值[重复]
【发布时间】:2014-10-28 16:14:54
【问题描述】:

考虑一下这个小代码

#include <stdio.h>
#include <stdlib.h>

void* foo1(double bar)
{
    double s2 = 0.5;
    double s1 = bar/s2;
    double toreturn[2] = {s1,s2};
    printf("Outside main. Second value: %f\n", toreturn[1]); //this line is commented out for the second output. See below text
    return toreturn;
}


int main()
{
    void* (*foo)(double) = NULL;
    foo = &foo1;
    double bar = 2.12;

    double* resp = foo(bar);
    printf("In main. First value: %f\n", resp[0]);
    printf("In main. Second value: %f\n", resp[1]);
    return 0;
}

代码输出

Outside main. Second value: 0.500000
In main. First value: 4.240000
In main. Second value: 0.500000

,这正是我所期望的。但是,如果我注释掉打印指令(foo1 定义中的指令),我会得到以下输出:

In main. First value: 4.240000
In main. Second value: 0.000000

,这对我来说毫无意义!对我来说,printf 命令可以更改变量的值似乎很奇怪。你能解释一下请解释一下这种行为吗?

【问题讨论】:

  • 尝试 %lf 而不是 %f
  • 另外,toreturn 是函数返回时消失的局部变量。
  • @Charlie Burns 注意:printf()doublefloat 打印与说明符 "%lf""%f" 相同。
  • 那一定是新的......就像在过去 20 年内一样。是因为浮点数在参数列表中被提升为双精度数吗?

标签: c function pointers printf


【解决方案1】:

这里的要点是不能从函数返回本地数组。数组toreturn 使用的内存在函数调用后是空闲的。它可以被任何函数调用覆盖,包括printf

使用malloc在函数中为你的数组分配内存并返回一个指向分配内存的指针,或者将数组作为参数传递。

【讨论】:

  • 好的,这是有道理的。但是我仍然不明白为什么printf 会覆盖内存?
  • @Remi.b:函数返回后,数组不再存在。在典型的实现中,为其分配的内存仍然存在,但它位于栈顶之上。 任何使用堆栈的 操作都可以重新分配相同的内存并破坏其值。行为未定义。
  • 我想编译器可以从你的函数中优化出一些赋值,因为如果你删除 printf,那么给数组赋值是没有意义的。比较带有和不带printf的汇编代码,我想会有区别。另外,尝试编译而不进行任何优化。但无论如何这都是错误的,这是未定义的行为,试图理解它为什么会这样或那样表现是没有意义的。
  • 非常感谢您的帮助! +1
  • 在这种特殊情况下,我会让函数接受两个参数,doubledouble *,然后从 main:double arr[2]; func(d, arr); 这样调用它,这样你就不用考虑内存分配了完全没有。
【解决方案2】:

您将void* 返回到在堆栈上分配的数组。一旦函数 foo1 返回,该内存将不再被分配,因此在 main 中使用 resp 是未定义的行为。

打印resp[0]resp[1] 是没有意义的,而且你不应该期待任何特定的输出,因为你有未定义的行为。

如果您想在 main 中使用该数组,您应该在 main 中声明它并将指向它的指针作为参数传递给您的函数:

double resp[2];
foo(bar, resp);

附带功能:

void foo1(double bar, double* resp)
{
    double s2 = 0.5;
    double s1 = bar/s2;

    resp[0] = s1;
    resp[1] = s2;
}

或者,您可以在 foo1malloc 中分配它并返回指向该分配内存的指针,但是您需要一种跟踪对 malloc 的每次调用的好方法,以便您可以在调用 free 时调用已经完成了。

【讨论】:

  • 非静态分配,堆栈分配
  • 如果它是静态分配的,那很好(不是线程安全的,但很好)。它是本地分配的。
  • @pm100:是的。更准确地说,它具有自动存储期限。
  • 感谢 Paulpro。您还在@atycnth 的答案下方的 cmets(现已删除)中回答了我的问题。 +1
猜你喜欢
  • 2011-12-05
  • 1970-01-01
  • 2020-09-01
  • 2021-05-27
  • 2021-10-17
  • 2015-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多