2012-05-14 89 views
2

我在这里遇到了一个真正奇怪的问题。当我使用手动打印语句来输出int * primesArr的值时,它工作(看似),但如果我尝试使用for循环执行此操作,它将失败。我通过gdb运行它,发现它正好在我将数组中的下一个单元格设置为值'k'的地方崩溃,这只发生在数字为素数时。第一次迭代成功(即2设置为primesArr [0]),然后在尝试增加数组时尝试程序Segfaults。但是这只有在使用for循环时才会发生。当我创建单独的打印语句时,我的程序按预期工作。我不知道如何/为什么我访问使用for循环时未被占用的内存。我确定我在某处执行过一些业余错误,这可能与我如何传递指针有关......但我无法确定它的确切根源。我会很感激任何帮助,并提前感谢您。指针分割错误

#include<stdio.h> 

int genPrimes(int seed, int *test){ 
    int inNumPrimes=0; 
    for(int k=0; k<=seed; k++){//k is number being checked for primeness 
     int cnt=0; 
     for(int i=1; i<=k; i++){//'i' is num 'k' is divided by 
      if(k%i == 0){ 
       cnt++; 
       if(cnt > 2){ 
        break; 
       } 
       }else{ 
      } 

     } 
     if(cnt == 2){ 
      printf("%i IS PRIME\n",k); 
      *test=k; 
      test++;//according to gdb, the problem is somewhere between here 
      inNumPrimes++;//and here. I'd wager I messed up my pointer somehow 
     } 
     //printf("%i\n",k); 
    } 
    return inNumPrimes; 
} 

int main(){ 
    int outNumPrimes=0; 
    int *primesArr; 
    int n = 0; 
    n=20; 

    outNumPrimes=genPrimes(n, primesArr); 
    printf("Congratulations! There are %i Prime Numbers.\n",outNumPrimes); 

    //If you print using this for loop, the SEGFAULT occurs. Note that it does not matter how high the limit is; its been set to many values other than 5. It will eventually be set to 'outNumPrimes' 
    //for(int a=0; a<5; a++){ 
    //printf("%i\n",primesArr[a]); 
    //} 

    //If you print the array elements individually, the correct value--a prime number--is printed. No SEGFAULT. 
    printf("%i\n",primesArr[0]); 
    printf("%i\n",primesArr[1]); 
    printf("%i\n",primesArr[2]); 
    printf("%i\n",primesArr[3]); 
    printf("%i\n",primesArr[4]); 
    printf("%i\n",primesArr[5]); 
    printf("%i\n",primesArr[6]); 
    printf("%i\n",primesArr[7]); 
    // 
    return 0; 
} 

输出,带手动声明:

$ ./a.out 
2 IS PRIME 
3 IS PRIME 
5 IS PRIME 
7 IS PRIME 
11 IS PRIME 
13 IS PRIME 
17 IS PRIME 
19 IS PRIME 
Congratulations! There are 8 Prime Numbers. 
2 
3 
5 
7 
11 
13 
17 
19 

现在for循环:

$ ./a.out 
2 IS PRIME 
Segmentation fault 

回答

5

线

int *primesArr; 

声明primesArr为指针变量,但它不分配任何内存。由于genPrimes()函数需要把它作为将充满首先准备一个空数组,你可以调用genPrimes()之前main()分配内存:

int primesArr[MAX_PRIMES]; 

int *primesArr = malloc(MAX_PRIMES * sizeof(int)); 

在这两种情况下,但是,您必须保证MAX_PRIMES足够大以容纳genPrimes()找到的所有素数,否则代码将会像现在一样产生错误。


其他提示:

1:复杂性

的唯一原因cnt必要的是k1k整除。如果更改

for (int i=1; i<=k; i++) { // 'i' is the number 'k' is divided by 

for (int i=2; i<k; ++i) { // 'i' is the number 'k' is divided by 

然后这两方面的情况下被淘汰,并且找到了其中k%i == 0i值环能尽快退出。

2:效率

测试

for (int i=2; i<k; ++i) { // 'i' is the number 'k' is divided by 

仍然有两个原因非常低效的。首先,不需要测试每个偶数;如果k > 2(k % 2) == 0,则k不能为素数。所以,你可以通过2(不是素数),明确检查2(素)或可分,然后利用

for (int i = 3; i < k; i += 2) { // 'i' is the number 'k' is divided by 

消除一半的测试,但你可以让这个仍然更有效,因为你可以停止达到sqrt(k)后。为什么?如果k可以被i整除,那么它也必须被k/i整除(因为i * k/i = k)。如果i > sqrt(k),然后k/i < sqrt(k)和循环已经退出。所以,你只需要

int r = (int) sqrt(k); 
for (int i = 3; i <= r; i += 2) { // 'i' is the number 'k' is divided by 

如果sqrt()不可用,则可以使用

for (int i = 3; i*i <= k; i += 2) { // 'i' is the number 'k' is divided by 

3:风格

只是一个简单的事情,但不是

int n = 0; 
n=20; 

你可以简单地写

int n = 20; 
+0

谢谢您的额外建议,他们很感激。按照您和其他人的建议,我可以通过显式初始化缓冲存储器来修复程序。谢谢! – shelladept

6

你逝去的未初始化的指针到您的素数的功能。你得到的行为是不确定的,这就是为什么这看起来很神秘。变量primesArr可能指向任何地方。

一个简单的情况就是这样,它很可能是更好的使用std::vector<int>

+0

谢谢你的std :: vector 建议。我将不得不考虑这一点。非常感谢。 – shelladept

1

您的primesArr变量未初始化。

声明一个指针

int *ptr; 

只是声明了一个指向int。但是,指针本身并不指向任何东西。就像声明

int val; 

不初始化val。因此,你需要为你的primesArr指针分配内存指向(与new或堆栈像int primesArr[N]在哪里N是一些大的数字。

然而,因为你不知道有多少质数你会从你的genPrimes功能先验和你没有说,STL是出了问题,我会考虑使用std::vector<int>作为输入到你的genPrimes功能:

int genPrimes(int seed, std::vector<int>& test) 

,并从功能中,你可以这样做:

test.push_back(k) 
+0

谢谢你扩展std:vector 。我将不得不考虑这一点,以尽可能减少我的缓冲区。谢谢! – shelladept