C程序停止响应大输入

时间:2014-03-12 18:43:16

标签: c arrays

我(重新)学习C并且在我正在阅读的书中我们正在讨论数组,本书给出了一个查找前n个素数的算法;我自己是一名数学家,并且是一些技术熟练的程序员,我决定使用不同的算法(使用Eratosthenes的筛子)获得前n个素数。好吧,算法运行良好,我的工作,甚至适度大的输入,即前50,000个素数需要一点运行,但没有问题。然而,当你开始弹出一个窗口弹出一个窗口,表示程序没有响应并且需要退出时,你几乎要说80,000个素数,我确保使得在素数上的变量是无符号long long int,所以我仍然应该在他们的价值观可接受的范围内。我做了一些粗略的在线浏览,其他有大量输入问题的人收到了建议在main之外创建变量的建议,以使它们成为全局变量。我尝试了一些我可以立即放在外面的变量,但这并没有解决问题。可能我需要将我的数组isPrime或primes放在main之外?但由于我的所有工作都是主要的,所以我无法真正看到如何做到这一点。

我意识到我应该用不同的功能做到这一点,但我只是按照我的方式编写它,但是如果我将所有内容都移到单独的函数中,那么我的数组仍然不是全局的,所以我不是。确定如何解决这个问题。

我尝试将它们设置为静态或外部,尝试将它们从堆栈内存中取出,但自然不会起作用,因为它们的数组会根据输入改变大小,并随着时间的推移而变化。

代码是:

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

unsigned long long int i,j;
unsigned long long int numPrimes,numPlaces;




int main(void)
{
    bool DEBUG=false;

    printf("How many primes would you like to generate? ");
    scanf("%llu",&numPrimes);

    // the nth prime is bounded by n*ln(n)+n*ln(ln(n)), for n >=6 
    // so we need to check that far out for the nth prime
    if (numPrimes>= 6)
        numPlaces = (int) numPrimes*log(numPrimes)+
                            numPrimes*log(log(numPrimes));
    else 
        numPlaces = numPrimes*numPrimes;

    if(DEBUG)
        printf("numPlaces: %llu\n\n", numPlaces);

    // we will need to check each of these for being prime
    // add one so that we can just ignore starting at 0
    bool isPrime[numPlaces+1];

    // only need numPrimes places, since that is all we are looking for
    // but numbers can and will get large
    unsigned long long int primes[numPrimes];

    for (i=2; i<numPlaces+1;i++)
        isPrime[i] = true; // everything is prime until it isn't

    i=2; // represents current prime
    while (i < numPlaces + 1)
    {
        for (j=i+1;j<numPlaces+1;j++)
        {
            if (isPrime[j] && j%i ==0) // only need to check if we haven't already
            {
                isPrime[j] = false;// j is divisibly by i, so not prime
                if(DEBUG)
                {
                    printf("j that is not prime: %llu\n",j);
                    printf("i that eliminated it: %llu\n\n",i);
                }//DEBUG if
            }//if
        }//for

        // ruled out everything that was divisible by i, need to choose
        // the next i now.

        for (j=i+1;j<numPlaces+2;j++)// here j is just a counter 
        {
            if (j == numPlaces +1)// this is to break out of while
            {
                i = j;
                break;
            }// if j = numPlaces+1 then we are done
            else if (isPrime[j]==true)
            {
                i = j;
                if (DEBUG)
                {
                    printf("next prime: %llu\n\n",i);
                }//DEBUG if
                break;
            }//else if
        }// for to decide i
    }//while

    // now we have which are prime and which are not, now to just get
    // the first numPrimes of them.
    primes[0]=2;
    for (i=1;i<numPrimes;i++)// i is now a counter
    {
        // need to determine what the ith prime is, i.e. the ith true
        // entry in isPrime, 2 is taken care of
        // first we determine the starting value for j

        // the idea here is we only need to check odd numbers of being
        // prime after two, so I don't need to check everything
        if (i<3)
            j=3;
        else if (i % 2 ==0)
            j = i+1;
        else
            j = i;

        for (;j<numPlaces+1;j+=2)// only need to consider odd nums
        {
            // check for primality, but we don't care if we already knew
            // it was prime
            if (isPrime[j] && j>primes[i-1])
            {
                primes[i]=j;
                break;
            }//if, determined the ith prime
        }//for to find the ith prime
    }//for to fill in primes

    // at this point we have all the primes in 'primes' and now we just
    // need to print them

    printf(" n\t\t prime\n");
    printf("___\t\t_______\n");

    for(i=0;i<numPrimes;i++)
    {
        printf("%llu\t\t%llu\n",i+1,primes[i]);
    }//for

    return 0;
}//main

我想我可以避免使用质数数组,只使用isPrime的索引,如果这会有帮助吗?任何想法都会有所帮助!

2 个答案:

答案 0 :(得分:2)

您分配的数组是堆栈变量(很可能),并且堆栈大小有限,因此您可能会在达到特定大小阈值时覆盖重要内容,从而导致程序崩溃。尝试使用分配有malloc的动态数组来存储筛子。

答案 1 :(得分:2)

您的问题在于此处,在VLA的定义中(“可变长度数组”,而非“非常大的数组”

    bool isPrime[numPlaces+1];

isPrime很大时,程序在数组numPlaces的局部变量区域中没有足够的空间。

您有两种选择:

  1. 在主函数之外声明一个“足够大”的数组,并忽略额外的空格
  2. 使用其他区域与malloc()和朋友
  3. 存储数组

    选项1

    #include <stdio.h>
    
    unsigned long long int i,j;
    bool isPrime[5000000]; /* waste memory */
    
    int main(void)
    

    选项2

    int main(void)
    {
        bool *isPrime;
    
        // ...
    
        printf("How many primes would you like to generate? ");
        scanf("%llu",&numPrimes);
    
        // ...
    
        // we will need to check each of these for being prime
        // add one so that we can just ignore starting at 0
        isPrime = malloc(numPrimes * sizeof *isPrime);
    
        // ... use the pointer exactly as if it was an array
        // ... with the same syntax as you already have
    
        free(isPrime);
        return 0;
    }