2

ここのコードで本当に奇妙な問題が発生しています。手動のprintステートメントを使用して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
4

3 に答える 3

6

初期化されていないポインタを素数関数に渡しています。あなたが得る振る舞いは未定義であり、それがこれがとても神秘的であるように見える理由です。変数primesArrはどこを指している可能性があります。

このような単純なケースでは、おそらくstd::vector<int>

于 2012-05-14T01:44:59.760 に答える
5

この線

int *primesArr;

ポインタ変数として宣言primesArrしますが、メモリを割り当てません。このgenPrimes()関数は、素数で埋められる空の配列として処理することを想定しているため、次をmain()呼び出す前にメモリを割り当てることができgenPrimes()ます。

int primesArr[MAX_PRIMES];

また

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

ただし、どちらの場合も、検出MAX_PRIMESするすべての素数を保持するのに十分な大きさであることを保証する必要がありgenPrimes()ます。そうしないと、コードは現在と同じようにエラーを生成します。


その他のヒント:

1:複雑さ

必要な唯一の理由cntは、とkで割り切れるということです。変更した場合1k

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

i次に、これらの両方のケースが排除され、ループは、の値が見つかるとすぐに終了できますk%i == 0

2:効率

テスト

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

2つの理由でまだかなり非効率的です。まず、すべての偶数をテストする必要はありません。k > 2との場合(k % 2) == 0k素数にすることはできません。したがって、2(素数)または2による除算(素数ではない)を明示的にチェックし、次に使用することで、テストの半分を排除できます。

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

ただし、に達した後に停止できるため、これをさらに効率的にすることができますsqrt(k)。なんで?kがいくつかの数で割り切れる場合、それは(=のために)iでも割り切れる必要があります。そして、の場合、ループはすでに終了しているはずです。だからあなただけが必要ですk/ii * k/iki > 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;
于 2012-05-14T01:49:59.970 に答える
1

primesArr変数は初期化されていません。

ポインタを次のように宣言する

int *ptr;

intへのポインタを宣言するだけです。ただし、ポインタ自体は何も指していません。宣言するのと同じように

int val;

valを初期化しません。したがって、primesArrポインタが指すメモリを割り当てる必要があります(newスタック上またはスタック上で、大きな数値がint primesArr[N]どこにあるかなど)。N

ただし、genPrimes関数からアプリオリに取得する素数がいくつあるかわからず、STLが問題外であるとは言っていないstd::vector<int>ため、genPrimes関数への入力としてaを使用することを検討します。

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

そして、関数内から、次のことができます。

test.push_back(k)
于 2012-05-14T01:52:59.740 に答える