【问题标题】:Why does this recursive function return the wrong value?为什么这个递归函数返回错误的值?
【发布时间】:2018-09-03 04:59:19
【问题描述】:

我在构建递归函数时继续遇到问题,该函数的返回值与我期望它返回的值不同。我相当肯定它与函数的递归性质有关,但我不明白发生了什么。

int foo(std::string, int = 0);

int main() {
std::string testString = "testing";
std::cout << foo(testString);
}

int foo(std::string givenString, int numberToReturn) {
    if (givenString.length() == 0) {
        std::cout << "Number to return before actually returning: " << numberToReturn << "\n";
        return numberToReturn;
    }
    if (true) {
        numberToReturn++;
    }
    std::string newString = givenString.erase(0, 1);
    foo(newString, numberToReturn);
}

在这个缩小的示例中,我有一个带有字符串的函数 foo 和一个默认值为 0 的 int。给定字符串“testing”并且没有整数,我希望递归函数为每次调用递增 numberToReturn 并传递下一次调用的新值。这一定是部分正确的,因为如果我在达到基本情况时 cout numberToReturn,我会得到预期值(在这种情况下它将是 7)。但是一旦我返回那个值,它就会变成一个更大的数字(在我的例子中是 6422160)。

话虽如此,为什么返回时数字会发生变化,我如何防止这种变化发生或返回正确/预期的值?

编辑:对于将来遇到类似问题的任何人,我的问题是每个 recursion 调用都必须返回一些东西,而不仅仅是最后一个。就我而言,返回函数 foo 的最后一行可以解决问题。不为每个函数调用返回某些内容会导致未定义的行为。

【问题讨论】:

  • "为什么返回时数字变了" 什么返回?仅当 givenString.length() == 0 为真时才返回 - 否则您将在函数末尾掉线而不返回任何内容,这是未定义的行为,
  • 更改编译器设置以捕获警告并将所有警告视为错误。它将为您省去很多麻烦。它会发现你现在遇到的问题。
  • @Algirdas 对不起,我不明白这个问题。如果我不返回,该函数会调用自身,直到基本情况为真。你能详细说明一下吗?
  • 那你什么也不返回。你觉得int f(int n) { if(n == 0) return 42; f(n - 1); }应该怎么做?
  • @PasserBy 我认为它会在 n + 1 调用时返回 42,不是吗?因为这似乎在这里工作。这如何转化为我稍长的示例?

标签: c++ recursion


【解决方案1】:

您的函数必须始终以 return 结尾,否则您的函数将返回一些随机的未初始化值。例如

int foo( int x )
{
  if ( x == 0 )
  {
    return x;
  }
  foo(x-1);
}

大致相当于:

int foo( int x )
{
  if ( x == 0 )
  {
    return x;
  }
  foo(x-1);
  return someRandomValue();
}

你真正想要的是:

int foo( int x )
{
  if ( x == 0 )
  {
    return x;
  }
  return foo(x-1);
}

【讨论】:

  • 没有。它不会“返回一些随机的未初始化值”,它被称为未定义行为
  • 感谢您的解释。我的印象是,只要在递归(第 n 次调用)结束时有返回,一切都很好,但似乎我需要在每次调用结束时始终返回。看起来这很容易解决,因为在您的示例中,您只需返回函数调用,这是有道理的。这听起来对吗?
  • @PasserBy 是的,根据标准返回值未定义的行为,但实际程序中的实际行为是根据调用约定返回一些随机值,这可能是当前存储的值在用于函数结果的任何寄存器中。我试图真正回答这个问题,而不是用标准语言来蒙蔽海报。
  • 不,你在误导别人。声称任何 UB 都是误导性的。 UB 不是你在 C++ 中忽略的东西。编译器确实利用这个特定的 UB,即使我们谈论的是实用性
  • @AlanBirtles Enjoy。现在停止发布明显不正确的内容。
猜你喜欢
  • 2022-12-06
  • 2018-10-19
  • 1970-01-01
  • 1970-01-01
  • 2023-04-09
  • 1970-01-01
  • 2020-11-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多