当数字范围超过40时,堆栈溢出错误

时间:2016-01-14 22:36:32

标签: c++ runtime-error overflow

该程序应该提示输入一系列数字,然后为该范围内的数字吐出变戏法序列,但每当我输入超过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;
} 

2 个答案:

答案 0 :(得分:1)

我看到的问题:

  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);
    
  2. 整数溢出

    pow调用返回的号码变得很大以适应long int时,下一次调用pow会导致错误。在我的测试环境中,数字163导致了这个问题。在某些时候,n的值达到-9223372036854775808并保持在那里,导致堆栈溢出。这非常接近LONG_MIN-9223372036854775807

  3. 我没有看到为什么n不会在奇数和偶数之间翻转的原因。这也会导致堆栈溢出。在前一种情况下,由于一系列奇数,n的值不断增加。

  4. 我能够通过将参数类型更改为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 "";
        }