该程序应该提示输入一系列数字,然后为该范围内的数字吐出变戏法序列,但每当我输入超过40的范围时,我得到一个堆栈溢出错误,不知道为什么谢谢 " juggler_seq.exe中0x77354A3E(ntdll.dll)的未处理异常:0xC00000FD:堆栈溢出(参数:0x00000001,0x00092FF4)。"
// juggler_seq.cpp:定义控制台应用程序的入口点。 //
#include "stdafx.h"
// Example program
#include <iostream>
#include <string>
#include <math.h>
#include <sstream>
#include <list>
template <typename T>
std::string to_string(T value){
std::ostringstream os;
os << value;
return os.str();
}
std::string jugglers(long int n, std::string ans = ""){
std::string num;
if (n == 1){
//checks for base case if 1 returns the seqence of numbers
return ans + "1";
}
else{
//checks for even odd
if (n % 2 == 0){
ans = ans + to_string(n) + ",";
//ans now adjusted to include most recent number calculated in the sequence
return jugglers(long int(pow(n, (1.0 / 2.0))), ans);
//passes the most recent number into the funtion again until the sequence converges to 1
//also passes the string ans with all previous numbers in sequence to keep track of numbers in the sequence
}
else{
num = to_string(n);
ans = ans + to_string(n) + ",";
return jugglers(long int(pow(n, (3.0 / 2.0))), ans);
}
}
}
int main()
{
int s, e;
int high = 0;
std::string usrstr;
std::list<std::string> ans;
std::list<std::string>::iterator it;
std::string n;
std::stringstream ss;
std::cout << "whats the starting point: ";
getline(std::cin, usrstr);
std::stringstream(usrstr) >> s;
std::cout << "\nwhats the end point: ";
getline(std::cin, usrstr);
std::stringstream(usrstr) >> e;
for (long int y = s; y != e + 1;y++){
ans.push_back(jugglers(y));
}
std::string com = "";
int count = 0;
int ref = 0;
for (it = ans.begin(); it != ans.end(); it++){
std::cout << *it<<std::endl;
std::string a = *it;
if (a.size()>com.size()){
com = a;
ref = count;
}
count += 1;
}
std::cout << "the ref is: " << ref + s << " the answer is : " << com << "\n";
return 0;
}
答案 0 :(得分:1)
我看到的问题:
语法。
return jugglers(long int(pow(n, (1.0 / 2.0))), ans);
应该是编译器错误。正确的方法是:
return jugglers((long int)(pow(n, (1.0 / 2.0))), ans);
或者,更好的是,
return jugglers(static_cast<long int>(pow(n, (1.0 / 2.0))), ans);
行
中存在同样的问题return jugglers(long int(pow(n, (3.0 / 2.0))), ans);
整数溢出
当pow
调用返回的号码变得很大以适应long int
时,下一次调用pow
会导致错误。在我的测试环境中,数字163导致了这个问题。在某些时候,n
的值达到-9223372036854775808
并保持在那里,导致堆栈溢出。这非常接近LONG_MIN
,-9223372036854775807
。
我没有看到为什么n
不会在奇数和偶数之间翻转的原因。这也会导致堆栈溢出。在前一种情况下,由于一系列奇数,n
的值不断增加。
我能够通过将参数类型更改为unsigned long
并将第一个检查更改为:
if (n <= 1){
但是,这只是一个黑客攻击。当n
到达整数溢出点时,任何后续代码都会受到未定义的行为。
在我的测试用例中,163
的输出是:
163,2081,94931,29249071,158186025767,62914706160224992,250828041,3972502044577,7917648072381635584,2813831564,53045,12217059,42702176063,8824193242915619,1
从输出中可以看出,终止是相当突然的不合逻辑。
答案 1 :(得分:1)
您的代码没问题。问题来自长整数溢出。
我在ideone上进行了一些额外的显示测试:使用n直到36,你的递归函数会收敛。使用37,您可以溢出long int可以容纳的最大值。然后,您的递归被破坏,没有收敛,从而触发堆栈溢出。
如果你使用long long
它会起作用(直到下一次的城市溢出):
std::string jugglers(long long int n, std::string ans = ""){
...
return jugglers((long long int)(pow(n, (1.0 / 2.0))), ans);
...
return jugglers((long long int)(pow(n, (3.0 / 2.0))), ans);
}
防止数字溢出导致堆栈溢出:
如果你想让它更强大,你可以尝试预测溢出:
jugglers()
的偶数分支上,您将使用较小的数字进行递归调用(因为将幂提高到1/2意味着平方根,并且此处n> 1)。所以没有什么不好的事情发生。 在奇数分支上,您将使用大于n的数字进行递归调用。如果存在整数溢出,则提高3/2的功率将计算小于当前值的数字。监控这种情况很容易,并停止并显示错误消息:
...
long long int r = (long long int)(pow(n, (3.0 / 2.0)));
if (r>n)
return jugglers(r, ans);
else {
std::cout<< "Integer overflow at "<<n<<std::endl;
return "";
}
...
这种方法在这里工作,但不是那么干净,因为你做了一个操作,导致数字溢出并在之后检测它。
另一种方法是在提升力量之前检查n是否会引起问题:
if (n>pow(std::numeric_limits<long long int>::max(), 2.0/3.0)) {
std::cout<<std::endl<<"Fatal error for "<<n<<std::endl;
return "";
}