2012-05-14 86 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