【问题标题】:Run-time error occurs when input value is greater than 100000输入值大于 100000 时发生运行时错误
【发布时间】:2016-10-20 07:24:43
【问题描述】:

我正在尝试在 C 中实现 Eratosthenes 筛选。该代码适用于小的输入值,但是一旦输入超出特定范围,就会引发运行时错误。这是 SPOJ 基础经典部分的第二个问题。什么错误?

#include<stdio.h>
#include<math.h>
int prime(unsigned long int, unsigned long int);
int main()
{
    int nitem;
    unsigned long int sn,fn;
    scanf("%d", &nitem);
    while(nitem)
    {
        scanf("%lu", &fn);
        //printf("%d",fn);
        scanf("%lu", &sn);

        prime(fn, sn);
        nitem--;
    }
    return 0;
}

int prime(unsigned long int fn, unsigned long int sn)
{
    unsigned long int prim[100000];
    int i,j,k;
    for(i = 0; i < 100000; i++)
    {
        prim[i] = 1;
    }

    prim[0] = 0;
    prim[1] = 0;
    //printf("%d", sn);
    //printf("%d", k);
    //printf("%d", (k <= sn));
    for(k = 2; k <= sqrt(sn); k++)
    {
    //  printf("alksnc%5d", k);
        if(prim[k] == 1)
        {

            for(j = 2; (k * j) <= sn; j++)
            {
                //printf("%d", prim[k]);
                prim[k * j] = 0;

            }
        }
    }



    for(int i = 0; i <= sn; i++)
    {
        if(prim[i] !=0 && i >= fn)
        {
            printf("%lu\n", i);
        }
    }
    printf("\n");

    return;
}

输入:

1
100000 100345

输出:

run time error

输入:

1
3 5

输出:

3
5

【问题讨论】:

  • 为什么是javac++
  • 请不要标记垃圾邮件。这是一个 C 程序。它不是 C++,也不是 Java。 MikeCAT 这次为您修复它,但请记住以备不时之需。
  • 不要访问超出范围的数组,否则会调用未定义的行为
  • 您的标题严重误导。您的崩溃示例输入是100000,而不是10000
  • 您将100345 传递给数组大小仅为100000 并使用prim[k * j] = 0; 进行索引的函数。您的迭代限制是(k * j) &lt;= snsn &gt;= 100000。根据需求为数组分配内存。

标签: c


【解决方案1】:

我们可以通过仅筛选奇数来更有效地利用内存 (2x),因为您处理的所有偶数都会浪费时间和空间。解决起来比较棘手,但给了我们类似的东西:

#include <math.h>
#include <libc.h>

#define MAX_ODD_PRIMES 1048576

void prime(unsigned long fn, unsigned long sn)
{
    unsigned char primes[MAX_ODD_PRIMES];

    for (unsigned long i = 0; i < MAX_ODD_PRIMES; i++)
    {
        primes[i] = TRUE;
    }

    primes[0] = 0; // preset first odd, '1'

    for (unsigned long k = 3; k <= sqrt(sn) + 1; k += 2)
    {
        if (primes[k / 2])
        {
            for (unsigned long j = 3; (k * j) <= sn; j += 2)
            {
                primes[k * j / 2] = FALSE;
            }
        }
    }

    if (fn <= 2)
    {
        printf("2\n");
        fn = 3;
    }

    for (unsigned long i = fn / 2; i * 2 + 1 <= sn; i++)
    {
        if (primes[i])
        {
            printf("%lu\n", i * 2 + 1);
        }
    }
}

示例

> ./a.out
1 1999900 2000000
1999957
1999969
1999979
1999993
>

【讨论】:

    【解决方案2】:

    1) 数组范围错误。

    通过更改代码

      for (j = 2; (k * j) <= sn; j++) {
        if (k * j >= 100000) {
          printf("Out of range %d %d\n", k, j);
          exit(1);
        }
        prim[k * j] = 0;
    
      }
    }
    

    输入 2, 100000
    输出

    Out of range 2 50000
    

    通过使用大小适合任务的数组 (VLA),可以避免这种情况。许多其他优化可用。还要考虑一个malloc() 数组。

    void prime(unsigned long int fn, unsigned long int sn) {
      unsigned long int prim[sn + 1];
    

    2) int prime() 最终执行 return; ,其中预期 return something;。建议改函数为void prime()

    int prime(unsigned long int fn, unsigned long int sn) {
        unsigned long int prim[100000];
        ...
        printf("\n");
        return;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多