【问题标题】:Is this a MinGW bug?这是一个 MinGW 错误吗?
【发布时间】:2010-06-16 07:48:22
【问题描述】:

我一直在尝试通过 Code::Blocks 在我的 MinGW 上执行这个程序:

#include <string.h>
#include <math.h>
#include <stdio.h>
#define N 100
int p[N];
int pr[N];
int cnt;

void sieve()
{
   int i,j;
   for(i=0;i<N;i++) pr[i]=1;
   pr[0]=pr[1]=0;

   for(i=2;i<N;i++)
      if(pr[i])
        {
         p[cnt]=i; cnt++;
         for(j=i+i;j<=N;j+=i) pr[j]=0;
        }

  }

int main(){
    sieve();
    int i;
    for(i=0;i<cnt;i++)
       printf("%d ",p[i]);
    puts("");
   printf("Total number of prime numbers : %d",cnt);
  return 0;
}

在我的系统上,输出是:

7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
素数总数:22

这完全是疯了,因为我完全确定我的算法的实现。

所以我决定在Ideone 中尝试它,它可以提供正确的输出。谁能指出原因?

我把它改成了N,但是输出没有变化。

【问题讨论】:

  • 为什么p只有两个元素? (N / 64?) 编辑:哎呀,我的数学很烂。这是一个元素。
  • @avakar 我虽然 100/64 会被截断为 1,所以这是一个大小为 1 的数组。我错过了什么吗?编辑:忍者编辑比我快。
  • 提示 - 编译器错误比您自己的代码中的错误少几个数量级 - 它们应该是您在尝试解决问题时考虑的最后一件事,而不是第一个。
  • 当有人问“ 中是否有错误?!”好的答案经常是:“不,再次检查您的代码”。

标签: c++ c mingw


【解决方案1】:

不,它实际上被称为 Debanjan 错误 :-) 看看 这个

#define N 100
int p[N / 64];

在我看来,您只允许足够的空间在p 数组中存储 一个 素数。这意味着为X &gt; 0 写入p[X] 可能会覆盖其他值。

这是可怕的未定义行为,这意味着任何事情都可能发生(包括它在 Ideone 情况下的工作)。

只需使用:

int p[N];

声明数组。我很确定不会有超过 100 个小于或等于 100 的素数 :-)

【讨论】:

  • 虽然这是一个一个 bug,你有没有测试过这个改变是否对输出有任何影响?
  • 不,我倾向于停止未定义的行为,只是因为那时所有的赌注都已取消。但是,既然你走得更远,发现了 实际 错误,这里给你一个赞成票。
【解决方案2】:

您的代码中有两个重要的错误。

一个是你的 p 数组太小了,所以你正在注销它的末尾。这是未定义的行为,尽管在您使用的平台上它会覆盖 pr 数组的开头。这对输出没有影响,因为您要覆盖的位置在您在筛子中测试的位置之前。

另一个是你也在注销你的 pr 数组的末尾:

        for(j=i+i;j<=N;j+=i) pr[j]=0;

此循环将pr[N] 设置为零,这超出了pr 的末尾。在 MinGW 中这是存储cnt 的地方,所以每次i 除以Ncnt 被设置为零。由于 N 是 100,i==2i==5 会发生这种情况,因此您会从结果中丢失 5 之前的素数。 IdeOne 似乎将cnt 放在与pr 相关的其他位置,因此它不会被覆盖。这就是为什么使用不同的编译器会得到不同的输出。

把数组p的大小改成N,或者筛子和输出都只用一个数组,把第18行的&lt;=改成&lt;,这样就不会把它的结尾写掉。

int p[N];
int *pr = p; // reuse the array

【讨论】:

  • 很好地了解pr的写作结束。
【解决方案3】:

您的数组 p 只有一个元素,因为您使用整数除法声明它 100/64

改成

int p[N];

或至少有 25 个元素的东西。

【讨论】:

  • 我想知道的是,为什么他的代码不会崩溃?他只是在这里幸运吗?
  • @Space,未定义的行为就是:未定义。从字面上看,这意味着任何事情都可能发生,包括整个多元宇宙的毁灭。 可能发生的许多事情之一是它会起作用:-)
  • @Space_C0wb0y 编译器碰巧把pr 放在p 旁边,所以注销p 的结尾只是写入pr,这是无害的-cnt 总是小于i,因此您甚至可以使用相同的数组进行筛选和输出。 真正的错误在别处。
  • @Space_C0wb0y:他走运了(或其他什么)。在我的测试运行中,我变得更加幸运——我得到了正确的输出。正如 pasdiablo 所说,未定义的行为意味着任何事情都可能发生。
  • @Pete Kirkham:无法保证编译器/链接器会按照您在源代码中看到的相同顺序放置变量。事实上,我使用的一个工具集几乎从不这样做——即使在调试版本中也是如此。
【解决方案4】:

没有。我不认为在这种情况下存在 MinGW 错误。

您的应用程序中存在错误。正如人们之前提到的,p 数组只有 1 个元素。 (处理整数值时为 100/64 = 1)。

这意味着当您在 p[1] 或 p[2] 或 p[3] 之后访问(超出数组边界)时,您实际上将在 p 这是 pr 数组。

使用 Ideone,我相信阵列的内存区域可能距离更远,而不是像 MinGW 案例中那样一个接一个(这只是一个假设)。

【讨论】:

    【解决方案5】:

    数组p 太小,你将超出它并写入pr

    变化:

    int p[N / 64];
    

    到:

    int p[N / 2];
    

    脚注:永远不要仅仅因为您看到无法立即解释的问题而假定编译器存在错误。 99.999% 的情况是你的 bug - 你只是还没有找到它。

    【讨论】:

      【解决方案6】:

      100/64 是 1。所以 p 只有一个元素 - p[0]。当您访问 p[1]、p[2] 等时,您开始覆盖 pr 数组中的元素。这会产生错误的结果。

      这是您程序中的错误,而不是 mingw 错误。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-09-18
        • 2012-03-25
        • 2010-12-22
        • 2023-03-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-09
        相关资源
        最近更新 更多