【问题标题】:Recursive Number Addition递归数加法
【发布时间】:2017-11-27 16:54:07
【问题描述】:

我遇到了一个看起来是胭脂总变量的问题。 sumDigits 函数的目标是将用户输入的每个数字递归地添加到将显示的总数中。我现在发现的是,当我传递对输入总计的引用时,也接受了该值。我能解释一下发生了什么吗?

我的代码分解成简单的语句:

#include <iostream>
using namespace std;

int sumDigits(int&);

int main()
{
int input = 123;
cout << sumDigits(input);
}

int sumDigits(int& input)
{
int total, newNumber;
if (input < 10)
return input;
else
{
newNumber = input%10;
total += newNumber;
input = input/10;
return sumDigits(input);
}
}

我在测试验证总数时的代码:https://pastebin.com/u1MS63Ji

当前代码的结果:

Welcome to the Sum of Digits Machine. Please type in your number or -1 to 
quit
enter a nonnegative integer: 1234
input: 1234 
Total: 1234  // total magically takes input value
newNumber: 0
Total: 1234
Total after: 1238 newNumber: 4  //total+=newNumber does its job.
input: 123
input: 123
Total: 1539161746 //how in the world? 1238 + 3 does not equal this....
newNumber: 32600
Total: 1539161746
Total after: 1539161749 newNumber: 3
input: 12
input: 12
Total: 1539161746
newNumber: 32600
Total: 1539161746
Total after: 1539161748 newNumber: 2
input: 1
input: 1
number is smaller than 10
the sum of all digits is: 1.
enter a nonnegative integer:  

有人可以向我解释一下为什么总在 sumDigits() 开始时会接收输入值吗?任何指出我做错了什么的指针都将不胜感激。

旁注:希望这个澄清解决了我的问题。如果不是管理员,请准确告诉我您想要什么,因为我显然是堆栈溢出的新手。我还应该解释我试图研究这个问题的反对票,但我运气不好。我还是个学生,对这方面很陌生。

【问题讨论】:

  • 是时候学习如何使用调试器了。
  • 我正在使用 Cloud 9,其中包含本机调试器。我已经追踪了两次,但仍然无法弄清楚它在哪里弄混了。
  • 把你的代码放在这里,而不是“pastebin”。这些链接随时可能失效,使这个问题在未来变得毫无价值。取出 cmets、cout's 和空行以供初学者使用。
  • 例如this is what your code reduces down to,因此它将是minimal reproducible example。现在,使用它,我们不会滚动浏览大量不必要的 cmets 和多余的 cout 行。此外,可能会发现以这种方式呈现的代码存在问题。
  • 明白了。我早些时候有点举手,因此为什么我把它放在目前的状态。谢谢指点。

标签: c++ recursion


【解决方案1】:

我认为这是“正常”(即标准)c++。我也只检查新代码。

小问题:您正在使用单元化变量: - 您正在第 27 行中对单元化变量进行 while 循环测试, - 您在第 82 行和第 83 行打印单元化变量,

养成始终初始化变量的习惯,例如:

int total = 0, newNumber = 0;

现在到算法:这是错误的。考虑第 82 - 90 行: 84:你计算数字值,好。 86:您将数字值添加到总计中,如果总计将被初始化,这将是一件好事。但是由于您要将总计初始化为零,因此不需要加法。 88:你计算递归调用的输入,这很好。您正在使用调用者通过引用传递给您的变量,这在递归算法中很棘手,但让我们坚持下去。 90:你递归调用。

你没有对第 84 行的数字值做任何事情(除了将它添加到另一个局部变量)...

试试这个:

return newNumber + sumDigits(input);

并在第 48 行使用返回值(而不是输入):

int inputDigitSum = sumDigits(input);

更新: 您正在尝试使用递归算法计算数字总和。这些都是出了名的棘手,难以解释和遵循。不过还是试试吧。

基本思路: 给定一些我们想要计算数字总和的整数值(输入),我们从中删除一个数字(最低数字,使用 % 运算符)。然后我们递归调用相同的函数,其值由剩余的数字组成(除以 10 的结果)。该调用将以某种方式返回剥离值的数字总和。然后我们将我们的数字添加到该值并将总和返回给我们的调用者。或以列表形式:

  1. 让 current_digit = input % 10 # 当前数字值
  2. 让剩余值 = 输入 / 10 # 位剩余数字
  3. 让 digit_sum = 递归调用的结果,如果剩余值至少为 10,则剩余值
  4. 返回 digit_sum + current_digit

让我们在数字输入 = 124 上试试这个:

 1. current_digit = 124 % 10 = 4
 2. remaining_value = 124 / 10 = 12
 3. recursive call with remaining_value = 12
 3.1. current_digit = 12 % 10 = 2
 3.2. remaining_value = 12 / 10 = 1
 3.3. recursive call with remaining_value = 1
 3.3.1. current_digit = 1 % 10 = 1
 3.3.2. remaining_value = 1 / 10 = 0
 3.3.3. no recursive call because remaining_value is less than 10
 3.3.4. return current_digit = 1
 3.4. return current_digit + call result = 2 + 1 = 3
 4. return current_digit + call result = 4 + 3 = 7

现在回到你的功能。

int sumDigits(int& input)
{
  int total, newNumber;
  if (input < 10)
    return input; // (1)
  else {
    newNumber = input%10;    // (2)
    total += newNumber;      // (3)
    input = input/10;        // (4)
    int tmp = sumDigits(input); // (5)
    return tmp;              // (6)
  }
}

让我们输入相同的数字 = 124:

2. newNumber = input%10 = 124%10 = 4
3. total += newNumber = random (total is unitialized, so its random + 4, still random)
4. input = input/10 = 124/10 = 12
5.2. newNumber = input%10 = 12%10 = 2
5.3. total += newNumber = random
5.4. input = input/10 = 12/10 = 1
5.4.1. return input = 1 (because its less than 10)
5.5. tmp = result of recursive call = 1
5.6. return tmp = 1
5. tmp = result of recursive call = 1
6. return tmp = 1

请注意,对 sumDigits 的每次调用都有自己的私有局部变量 total 和 newNumber,它们之间没有任何关联。这就是为什么我建议返回 newNumber 的总和(应该称为 lastDigit 或类似的东西),这是最不重要的数字和递归调用的结果,它应该返回其他剩余数字的总和。

【讨论】:

  • 我在跟踪你时遇到了一些麻烦。当变量在每次递归期间初始化为 0 时,每次我的总数为 0 时,它都会消除将所述变量添加到我的总数中的工作。我如何让我的总数不在递归中,或者更好但实际上赋予它能力做我要求的工作。似乎即使我将 newNumber 添加到递归 sumDigits() 它总是会回到 0。你能澄清你在说什么吗?
  • 此外,当总计初始化为 0 时,它并不能真正解释当我没有将总计值分配为具有输入值时如何或为什么自动成为输入......
  • 啊。不,它不是那样工作的。默认情况下,函数变量(total 和 newNumber)都是所谓的本地变量。对 sumDigits 的每次调用都会获得这些变量的自己的副本。因此,当您递归调用 sumDigits 时,每个调用都有自己的副本。初始化它不会修改其他“副本”。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-03-07
  • 1970-01-01
  • 2012-10-22
  • 2017-08-09
  • 2013-03-23
  • 1970-01-01
  • 2016-12-13
相关资源
最近更新 更多