【问题标题】:Sieve of Eratosthenes algorithm in CC中的埃拉托色尼筛算法
【发布时间】:2013-03-20 16:50:24
【问题描述】:

好的,所以我创建的这个函数使用埃拉托色尼筛算法来计算所有素数

当函数退出时,素数应该指向一块动态分配的内存,其中包含所有素数*count 将有素数的计数。

这是我的函数getPrimes

void getPrimes(int num, int* count, int** array){
    (*count) = (num - 1);
    int sieve[num-1], primenums = 0, index, fillnum, multiple;

    //Fills the array with the numbers up to the user's ending number, num.
    for(index = 0, fillnum = 2; fillnum <= num; index++, fillnum++){
        sieve[index] = fillnum;
    }

    /* Starts crossing out non prime numbers starting with 2 because 1 
       is not a prime. It then deletes all of those multiples and 
       moves on to the next number that isnt crossed out, which is a prime. */
    for (; primenums < sqrt(num); primenums++)  //Walks through the array.
    {
        //Checks if that number is NULL which means it's crossed out
        if (sieve[primenums] != 0) {
            //If it is not crossed out it starts deleting its multiples.
            for (multiple = (sieve[primenums]); 
                 multiple < num; 
                 multiple += sieve[primenums]) {  
                //Crossing multiples out 
                //and decrements count to move to next number
                sieve[multiple + primenums] = 0;
                --(*count);
            }
        }
    }
    int k;
    for(k=0; k < num; k++)
        printf("%d \n", sieve[k]);

    printf("%d \n", *count);
    array = malloc(sizeof(int) * (num + 1));
    assert(array);
    (*array) = sieve;
}

现在,这是预期的输出和我的输出。如您所见,我的 getPrimes 函数中有问题,但我不确定是什么。

预期输出: 小于或等于 19 的素数有 8 个 2 3 5 7 11 13 17 19 我的输出: 2 3 0 5 0 7 0 0 0 11 0 13 0 0 0 17 0 19 0 0

到目前为止,人们向我指出了以下 3 个问题:

  1. 错误的删除过程if (sieve[multiple]) {数组筛子索引有偏差
  2. (*array) = sieve; 泄漏刚刚分配的内存,并让 *array 指向一个在函数返回时不再存在的局部变量 - 你会得到一个悬空指针。
  3. if(sieve[i] != NULL) 应该使用 0,而不是 NULL,因为你没有指针数组。

但是,我不太确定如何解决已为我发现的悬空指针/内存问题。除此之外,我想知道我的代码中是否还有其他错误,因为我不太清楚为什么我的输出中的数字添加了 0...不要担心不同的输出样式,只需担心额外的数字.谢谢你能帮我解决这个问题!

【问题讨论】:

    标签: c primes sieve-of-eratosthenes sieve dangling-pointer


    【解决方案1】:

    您要打印的数字属于筛子,因此所有非质数都设置为0。尝试按以下方式打印

    for (k = 0; k < num; k++)
    if (sieve[k] != 0)
    {
            printf(" %d\n", sieve[k]);
    }
    printf("\n");
    

    此外,您不应通过array 参数返回本地数组sieve,因为它位于堆栈上,并且在函数返回时将不再可用。

    【讨论】:

    • 你的回答实际上解决了我的问题......但现在我得到了超过 99 的任何数字的分段错误。
    【解决方案2】:
    void getPrimes(int num, int* count, int** array){
        (*count) = (num - 1);
        int sieve[num-1], primenums = 0, index, fillnum, multiple;
    

    您正在声明一个由num-1 元素组成的数组,用于从2 到num 的数字。没关系。

        //Fills the array with the numbers up to the user's ending number, num.
        for(index = 0, fillnum = 2; fillnum <= num; index++, fillnum++){
            sieve[index] = fillnum;
        }
    

    您正在用与之关联的数字填充每个插槽,也可以。

         /* Starts crossing out non prime numbers starting with 2 because 1 is not a prime.
            It then deletes all of those multiples and 
            moves on to the next number that isnt crossed out, which is a prime. */
         for (; primenums < sqrt(num); primenums++) //Walks through the array.
    

    您大致停在平方根处,这很好。

            {
                if (sieve[primenums] != 0){ //Checks if that number is NULL which means it's crossed out
    
                       for (multiple = (sieve[primenums]); multiple < num; multiple += sieve[primenums])
                          //If it is not crossed out it starts deleting its multiples.
                       {  //Crossing multiples out and decrements count to move to next number
                                sieve[multiple + primenums] = 0;
    

    你在这里遇到了问题。您只在multiple &gt;= num 时停止循环,但您正在写入索引multiple + primenums,并且通常超出数组的末尾。例如,使用num == 19primenums == 1(删除3 的倍数),最后一次写入是索引18 + 1,但最后一个有效索引是num - 2 = 17

    第 1 点的索引偏差已修复。但是

                                --(*count);
    

    您在这里无条件地递减*count,在之前的代码中,您仅在sieve[multiple] 尚未被划掉时才递减它。这才是正确的方法。我建议

    for(multiple = primenums + sieve[primenums]; multiple < num - 1; multiple += sieve[primenums]) {
        if (sieve[multiple]) {
             sieve[multiple] = 0;
             --(*count);
        }
    }
    

    让它更简单一点。

                       }
                }
            }
            int k;
            for(k=0; k < num; k++)
                printf("%d \n", sieve[k]);
    

    无论是否为0,您都在打印sieve 的内容,并且您还打印出不存在的sieve[num - 1]。实现它

    for(k = 0; k < num-1; ++k) {
        if (sieve[k]) {
            printf("%d\n", sieve[k]);
        }
    }
    

    只打印素数。

                printf("%d \n", *count);
            array = malloc(sizeof(int) * (num + 1));
             assert(array);
             (*array) = sieve;
    }
    

    (*array) = sieve 替换为

    int i = 0;
    for(k = 0; k < num-1; ++k) {
        if (sieve[k]) {
            (*array)[i] = sieve[k];
            ++i;
        }
    }
    

    只将素数写入*array。此外,您无需为此分配(num + 1)*sizeof(int),而只需分配*count * sizeof(int)

    【讨论】:

    • 很好的答案!非常彻底和乐于助人
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-16
    相关资源
    最近更新 更多