0

我有一个玩具密码程序,当给定一个很长的密钥时遇到总线错误(我正在使用 961168601842738797 来重现它),这让我感到困惑。当我注释掉部分以隔离错误时,我发现它是由我的 Sieve of Eratosthenes 中的这个无辜的循环引起的。

unsigned long i;
int candidatePrimes[CANDIDATE_PRIMES];
// CANDIDATE_PRIMES is a macro which sets the length of the array to
// two less than the upper bound of the sieve. (2 being the first prime
// and the lower bound.)

for (i=0;i<CANDIDATE_PRIMES;i++)
{

  printf("i: %d\n", i); // does not print; bus error occurs first

  //candidatePrimes[i] = PRIME;

}

有时这是分段错误而不是总线错误。

谁能帮助我了解正在发生的事情以及将来如何解决/避免它?

提前致谢!

附言

完整代码可在此处获得:

http://pastebin.com/GNEsg8eb

4

2 回答 2

2

我会说你的 VLA 对你的堆栈来说太大了,导致未定义的行为。

最好动态分配数组:

int *candidatePrimes = malloc(CANDIDATE_PRIMES * sizeof(int));

并且在返回之前不要忘记free

如果这是 Eratosthenes Sieve,那么数组实际上只是标志。如果它只是保持 0 或 1,那么使用它是浪费int的。至少使用char(为了速度),或者浓缩到一个位数组(为了最小化存储)。

于 2013-11-07T01:40:56.667 回答
1

问题是你把堆栈吹走了。

unsigned long i;
int candidatePrimes[CANDIDATE_PRIMES];

如果 CANDIDATE_PRIMES 很大,这会大量改变堆栈指针。但它并没有触及内存,它只是将堆栈指针调整了一个非常大的量。

for (i=0;i<CANDIDATE_PRIMES;i++)
{

这会调整“i”,它回到堆栈的良好区域,并将其设置为零。检查它是否 < CANDIDATE_PRIMES,它是,因此执行第一次迭代。

printf("i: %d\n", i); // does not print; bus error occurs first

这试图将“printf”的参数放在堆栈的底部。繁荣。内存位置无效。

CANDIDATE_PRIMES 有什么价值?

而且,你真的想存储你正在测试的所有素数还是只存储那些通过的素数?将值 0 到 CANDIDATE_PRIMES 顺序存储在数组中的目的是什么???

如果您只想存储素数,则应使用动态分配并根据需要进行增长。

size_t g_numSlots = 0;
size_t g_numPrimes = 0;
unsigned long* g_primes = NULL;

void addPrime(unsigned long prime) {
    unsigned long* newPrimes;
    if (g_numPrimes >= g_numSlots) {
        g_numSlots += 256;
        newPrimes = realloc(g_primes, g_numSlots * sizeof(unsigned long));
        if (newPrimes == NULL) {
            die(gracefully);
        }
        g_primes = newPrimes;
    }
    g_primes[g_numPrimes++] = prime;
}
于 2013-11-07T01:49:42.440 回答