【问题标题】:Recursion in C only works when printing unrelated thingsC 中的递归仅在打印不相关的内容时才有效
【发布时间】:2017-05-14 03:42:45
【问题描述】:

我刚开始学习 C,我决定在 Euler Problems 上做一些练习。 不工作的程序旨在解决问题 2,它要求计算所有低于 4,000,000 的偶数斐波那契数的总和。

这个程序真正奇怪的是它确实有效,但前提是我在递归期间打印一些东西:每当我尝试在递归函数中注释掉 printf("bazooka"); 行时,我得到的结果似乎完全随机,并且在连续执行同一程序时出现大的正数和大的负数(例如 -882154758 和 770491113)。 另一方面,如果我在递归函数中打印一些东西,无论如何,我都会得到正确的输出。

我发现这种行为非常奇怪和有趣,我真的很想知道发生了什么:真正让我感到困惑的是,即使程序根本没有改变,输出的数字也会发生变化。另外,我不明白为什么在递归期间打印会对正在执行的整数计算产生任何影响。

这是我的主要功能:

int first = 1; int second = 2; int total = 0;
total = Fibo(first,second, total);
printf("\nthis is my result for Euler 2: ");
printf("%d",total);

这是我的递归函数:

  int Fibo(int first, int second, int total) {
  printf("bazooka");
  if (second < 4000000) {
    int add;
    second = first+second;
    first = second-first;
    if (first%2 == 0) {
      add = first;
    }
      total = add+Fibo(first,second,total);
  }
  return total;
}

谁能帮我解决这个问题?非常感谢您的帮助。

【问题讨论】:

  • 你需要初始化int add = 0;。否则,它可以(并且显然确实)采用恰好写入存储在行total = add+Fibo(first,second,total); 中的任何值
  • 即使有你的bazooka 修复,我也会得到-1900183196。这肯定是错的。
  • 一个递归函数完全过度杀戮。把这个技巧留给更难的问题吧。一个简单的循环就可以做到。因为限制是 4000000 int 对于 32 位机器来说已经足够了。
  • @andy_programs 正如 Rad Lexus 指出的那样,它并没有真正解决它(至少不是以可靠的方式) - 它可能只是对您调用的特定系统的副作用printf 更改了后来被add 占用的内存位置中的值。虽然不能保证这种行为
  • 不,不是,它建议您放弃解决方案并重新开始,因为编程是为了找到最简单的解决方案。通过问题的难度来培养你的技能,而不是让它们变得更复杂。

标签: c recursion printf fibonacci


【解决方案1】:

如果first 是奇数,则不会初始化add。确保在这两种情况下都初始化变量,错误就会消失。

现在,为了解释观察到的行为:使用未初始化的变量可以显示为随机“值”,或者它可能导致程序以其他随机方式发生故障。 (类 C 语言中的技术术语是 undefined behavior。)在您的情况下,该值很可能是以前使用用于函数堆栈帧的内存位置或以前的值留下的垃圾的寄存器。调用printf 似乎可以解决问题,因为它的实现碰巧使用并清除了内存的相关部分。不用说,这不是你可以依赖的。

请注意,编译器将使用适当的警告设置来诊断此类错误,例如用于 GCC 或 Clang 的 -Wall

【讨论】:

    【解决方案2】:

    好吧,我不能 100% 地关联这种行为,但可以肯定的是,当你得到像负数这样的数字时,是因为你超过了 int 值的最大值:

    INT_MIN = -2147483648 
    INT_MAX = +2147483647
    

    将此类型更改为long,如果得到相同的结果,则更改为long long

    Here你可以检查数据类型边界。

    【讨论】:

    • 这是一个合理的猜测,但正如您从另一个答案中看到的那样,这不是原因。检查这是否是问题的一个好方法是实际打印出中间值;这样做表明它永远不会达到那么高。
    • 碰巧,int 对于problem 来说已经足够了。
    • 忽略我之前的评论,您的链接中显示的值似乎很奇怪并且不是很有代表性。我更喜欢cppreference 而不是 cplusplus.com 的原因之一——那里的信息通常更准确。 (另外INT_MININT_MAX 实际上不是常量,它们取决于编译器)
    猜你喜欢
    • 2021-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-02
    • 1970-01-01
    • 2019-01-15
    • 1970-01-01
    相关资源
    最近更新 更多