埃拉托色尼筛法 C 实现错误

Sieve of Eratosthenes C implementation error

所以我正在做下一个作业,将输入数字分解为输出中的素数乘法。当它只显示素数 2 时我很困惑,所以我使用这个函数对分配的素数数组进行了适当的控制转储:

long* eratosthen(long max) {
    bool grid[max + 1];

    for(long i = 0; i < max + 1; ++i) {
        grid[i] = true;
    }

    for(long i = 2; i < max + 1; ++i) {
        if(grid[i]) {
            for(long j = i * 2; j < max + 1; ++j) {
                grid[j] = false;
            }
        }
    }

    long *primes;
    primes = (long*)malloc((max + 1) * sizeof(long));

    long index = 0;
    for(long i = 2; i < max + 1; ++i) {
        if(grid[i]) {
            primes[index++] = i;
        }
    }

    return primes;
}

出于某种未知原因,转储仅显示 2 并结束。调用转储由以下代码组成:

int main(void) {
    // Prime numbers get calculated first
    long *primes;
    primes = eratosthen(1000000);

    // Control code
    fprintf(stdout, "Control dump of primes array:\n");
    for(long i = 0; i < sizeof(primes) / sizeof(long); ++i) {
        fprintf(stdout, "%li\n", primes[i]);
    }
    int ret = 0;
    /// ...
    return ret;
}

//编辑:所以在你回答完所有问题后,我会将我的问题更新为当前状态。主要程序: int 主要(无效){ // 首先计算素数 长*素数; 素数 = eratosthen(1000000);

    // Control code
    fprintf(stdout, "Control dump of primes array:\n");
    for( ; *primes != 0 ; primes++) {
        fprintf(stdout, "%li\n", *primes);
    }
    int ret = 0;
}

生成素数函数:

long* eratosthen(long max) {
    bool *grid;
    grid = (bool*)malloc((max + 1) * sizeof(bool));

    index = 0;
    for(long i = 0; i < max + 1; ++i) {
        *(grid + index) = true;
        index++;
    }

    index = 2;
    index_2 = 2;
    for(long i = 2; i < max + 1; ++i) {
        if(*(grid + index)) {
            for(long j = i * 2; j < max + 1; j += i) {
                *(grid + 2 * index_2) = false;
                index_2++;
            }
            index++;
        }
    }

    long *primes;
    primes = (long *)malloc((max + 1) * sizeof(long));

    index = 0;
    for(long i = 0; i < max + 1; ++i) {
        *(primes + index) = 0;
        index++;
    }

    index = 0;
    index_2 = 2;
    for(long i = 2; i < max + 1; ++i) {
        if(*(grid + index_2)) {
            *(primes + index) = i;
            index++;
            index_2++;
        }
    }

    // free the grid
    free(grid);

    return primes;
}

如前所述,Ubuntu 终端显示以下行:

Neoprávněný přístup do paměti (SIGSEGV) (core dumped [obraz paměti uložen])

翻译成这样:

Forbidden access to memory (SIGSEGV) (core dumped [memory image saved])

这是什么意思以及如何摆脱它? :(

最简单的代码修复可能是在素数数组的末尾添加标记值 0,并重写 main() 中的检查条件。正如评论中广泛解释的那样,您当前的测试:

for(long i = 0; i < sizeof(primes) / sizeof(long); ++i) {

大错特错。您不得尝试使用 sizeof,因为它根本不会执行您希望它执行的操作。

此代码有效:

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

static
long *eratosthen(long max)
{
    bool grid[max + 1];

    for (long i = 0; i < max + 1; ++i)
        grid[i] = true;

    for (long i = 2; i < max + 1; ++i)
    {
        if (grid[i])
        {
            for (long j = i * 2; j < max + 1; j += i)   // Key fix
                grid[j] = false;
        }
    }

    long *primes;
    primes = (long *)malloc((max + 1) * sizeof(long));

    long index = 0;
    for (long i = 2; i < max + 1; ++i)
    {
        if (grid[i])
            primes[index++] = i;
    }
    primes[index] = 0; // Sentinel

    return primes;
}

int main(void)
{
    // Prime numbers get calculated first
    long *primes = eratosthen(1000000);

    fprintf(stdout, "Control dump of primes array:\n");
    for (long i = 0; primes[i] != 0; ++i)
    {
        printf("%7li", primes[i]);
        if (i % 10 == 9)
            putchar('\n');
    }
    putchar('\n');
    return 0;
}

我修改了代码,每行打印 10 个数字。我在 main() 中更改了循环中的条件。我在函数中做了两个关键更改——一个是正确计算素数的倍数,另一个是在素数列表的末尾添加标记。

它生成一个包含 78,498 个以

开头的素数的列表
      2      3      5      7     11     13     17     19     23     29
     31     37     41     43     47     53     59     61     67     71
     73     79     83     89     97    101    103    107    109    113

并以:

结尾
 999563 999599 999611 999613 999623 999631 999653 999667 999671 999683
 999721 999727 999749 999763 999769 999773 999809 999853 999863 999883
 999907 999917 999931 999953 999959 999961 999979 999983

您可能会注意到该代码并未发布 primes — 可以说应该发布。您可能会注意到分配给质数的 space 大大超过了所需的 space(一百万对少于八万);您可以使用 realloc() 来缩小分配的 space,或者使用不那么保守(或者我的意思是不那么挥霍?)估计所需的条目数。