【问题标题】:How to deal with this segmentation fault in C++?如何处理 C++ 中的这种分段错误?
【发布时间】:2014-04-10 22:06:51
【问题描述】:

我需要计算一个大素数模的阶乘。 我的程序可以达到某些值,但是当我达到程序中提到的更高值时它会失败(分段错误)。

我怎样才能使这个程序工作?

非常感谢

#define LL unsigned long long
#define ull unsigned long long

const LL mod=1000000009;

LL arr[1048580];

inline ull mulMod(ull a,ull b,ull c)
{
    if(a<=1000000000ULL && b<=1000000000ULL)
    {
        //cout<<((a%c)*(b%c))%c<<endl;
        ull ret = ((a%c)*(b%c))%c;
        return ret;
    }
    ull ret = 0ULL; a=a%c;

    while(b > 0ULL)
    {
        if(b&1ULL) ret = ((ret%c)+(a%c))%c;
        a = (a<<1ULL)%c;
        b>>=1ULL;
    }
    return ret%c;
}

LL fact(LL num)
{
    if(arr[num]==0)
    {
        arr[num]=mulMod(num,fact(num-1),mod);
        return arr[num];
    }
    return arr[num];
}


int main()
{
    arr[0]=1;
    cout<<fact(325720);

}

【问题讨论】:

  • 段错误发生在哪里?
  • 由于fact(n) 递归调用fact(n-1),通过调用fact(325720),您正在向系统请求大小为325720 的调用堆栈。这是行不通的。它太大了。
  • 你为什么使用#define 来表示类型别名(可怕的想法!),为什么同一事物有两个不同的名称?

标签: c++ segmentation-fault factorial


【解决方案1】:

你有一个堆栈溢出!

在递归调用mulMod()时发生段错误。

如果你想让它适用于大数,你应该避免递归。一个简单的for循环实现:

LL fact2(LL num)
{
    int i;
    for (i = 1; i < num; ++i) {
        arr[num] = mulMod(num,arr[num-1],mod);
    }
    return arr[num];
}

【讨论】:

    【解决方案2】:

    你可以:

    • 通过要求您的操作系统加载程序安排更宽松的堆栈大小限制来移动失败的阈值(例如,尝试来自 Linux/Unix shell 的ulimit 命令 - 请参阅here),或者

    • 重写您的算法或更改编译器优化选项,使其实现tail recursion 优化(如果您发现您的特定算法和编译器可能实现),或者

    • 编写一个使用for/while而不是递归的迭代解决方案。

    【讨论】:

      【解决方案3】:

      您的代码存在三个关键问题。显而易见的一个是您遇到的堆栈溢出。另一个是您通过不填充数组来调用未定义的行为。第三个是如果你调用函数fact 的数字大于或等于1048580,你将调用未定义的行为。

      通过跟踪数组大小和已设置的最后一个元素,这将有助于解决最后两个问题。

      const LL arr_size = 1048580;
      LL last_arr = 0;
      LL arr[arr_size] = {1,0};
      

      堆栈溢出问题是由对fact 的递归(非尾递归)调用引起的。这可以做成一个循环。请注意,我也在防止超出您的数组大小的数字。

      LL fact(LL num)
      {   
          if (num >= arr_size) {
              LL result = fact(arr_size-1);
              for (LL ii = arr_size; ii <= num; ++ii) {
                  result = mulMod(ii,result,mod);
              }   
              return result;
          }   
      
          if (num > last_arr) {
              for (LL ii = last_arr+1; ii <= num; ++ii) {
                  arr[ii] = mulMod(ii,arr[ii-1],mod);
              } 
              last_arr = num;  
          }   
      
          return arr[num];
      }   
      

      注意:这是递归定义到迭代定义的直接转录。有一些方法可以更有效地做到这一点。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-04-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-11-18
        • 1970-01-01
        相关资源
        最近更新 更多