筛选Eratosthenes C实施错误

时间:2016-11-06 05:49:42

标签: c implementation sieve-of-eratosthenes

因此,我正在制作下一个作业,输入数字将被解散,以便在输出中进行素数乘法。当它只显示素数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 main(void){         //首先计算素数         长*素数;         primes = 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])

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

1 个答案:

答案 0 :(得分:3)

对代码的最简单修复可能是在素数数组的末尾添加一个0的sentinel值,并在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 - 它可以说是应该的。你可能会注意到为素数分配的空间大大超过了所需的空间(一百万而不是八万);您可以使用realloc()缩小分配的空间,或者使用较不保守(或者我的意思是减少挥霍?)估计所需的条目数。