【问题标题】:Seg Fault When Initializing Array in C++ (Project Euler Number 3)在 C++ 中初始化数组时出现 Seg 错误(Project Euler Number 3)
【发布时间】:2013-10-28 04:14:39
【问题描述】:

所以我正在尝试编写一个程序来解决最大素数的 Project Euler 问题,虽然我知道代码在结构上是正确的(只要它返回较小数字的正确答案,包括他们给出的示例 13195 ),当我输入我们应该解决的数字时,我一直收到分段错误,即 600851475143。代码如下:

#include <stdio.h>
#include <math.h>

main(){
    int number,a,b,c,i,j,n,gpf;
    printf("Input number to analyze: ");
    scanf("%d",&number);
    a = number/2;
    printf("%d\n",a);
    int* primesieve = new int[a+1];               /*IMPORTANT LINE*/
    for (i=0;i<a+1;i++){
        primesieve[i] = 1;
    }
    for (j=2;j<=a;j++){
        if (primesieve[j] == 1){
            for (c=2;j*c<=a;c++){
                primesieve[j*c] = 0;
            }
        }
    }
    for (n=2;n<=a;n++){
        b = number/n;
        printf("%d\n",b);
        if (number % n == 0){
            if (primesieve[b] == 1){
                gpf = b;
                n = a+1;
            }
        }
    }
    delete[] primesieve;
    printf("The greatest prime factor of %d is %d.\n",number,gpf);
}

问题来自于初筛数组的初始化,因为我省略了那一行之后的所有行,但仍然遇到问题。我最初使用以下代码声明了该数组,该代码返回了低至 1000 万的值的分段错误。

int primesieve[a+1];

我在此站点上搜索了一个解决方案,该解决方案产生了对动态数组分配的更改,但是虽然这解决了 1000 万个问题,但显然没有解决更大的值。我注意到的其他解决方案提到了一些关于使用 malloc() 或在 main() 之外静态声明数组的内容,但坦率地说,我不理解这些,因为我的入门编程课程几乎没有提到 malloc(),我认为导致声明的代码需要包含在 main() 中的数组。 (供参考:Segmentation Fault While Creating Large Arrays in CSeg Fault when initializing array。)我确信这是一个相当简单的问题,但我是一个相对较新的程序员,因此对分配内存的理解很差,所以任何建议、解决方案或解释我发现的其他解决方案将不胜感激。

【问题讨论】:

  • 好的,所以你们俩都说“普通”计算机上不可能有这么大的筛子?由于我不会仅仅为了回答 Project Euler 问题而使用高端计算机,有没有更好的方法来处理超越位图和省略偶数的筛选?也许是零碎的?编辑:我应该在上面提到这一点 - 我在 4GB 的 Vista 64 上,并通过 Cygwin 运行程序。
  • 好的,我看到筛子对于这个数量级来说根本不可行。我会尝试不同的方法,即使这个算法显然适用于较小的数字。感谢您在下面给出的每个答案。
  • 如果你打算编写 C++ 代码,我强烈建议你看看 The book list
  • 你解决了小数字,这是一个很好的第一步,但随后他们扩大了规模,以至于没有人有足够的内存来暴力破解。这就是 Euler 项目的全部意义所在。

标签: c++ c arrays


【解决方案1】:

您的经验与编译器的物理限制和精度有关。 第一次尝试,在栈上分配数组

int primesieve[a+1];

很快就失败了,因为在大多数系统上,与堆相比,堆栈的大小相当有限。

在堆上分配

int* primesieve = new int[a+1]; 

为您提供更多空间,但您仍然有可寻址内存的限制。现在,600851475143 是一个相当大的数字,即使您将其除以 2。假设 int 的大小为 4 个字节,您可能想知道,您是否真的可以处理这么多内存。 使用 32 位,您可以寻址 2^32 = 4294967296 字节。

【讨论】:

    【解决方案2】:
    600851475143 * sizeof(int64_t) = 4806811801144 = 4.4TB
    

    换句话说,除非您有 5TB 的 RAM,否则此代码将始终崩溃。

    如果您使用位图作为筛子,您可以让它更容易忍受。 例如,每个数字使用 1 位,而不映射偶数只需要 600851475143 / 8 / 2 = 35GB 的 RAM。仍然很多,但如果你有钱买硬件的话是可行的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-18
      • 2012-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多