-1

私は C++ を初めて使用し、どこから始めればよいかわかりません。そのため、コードが大量にあるため、コードをペーストビンにアップロードしました。

このコードは正常にコンパイルされ、gcc の -Wall オプションを使用しても警告は発せられません。

コマンドラインパラメータとして指定された数までのすべての素数を生成することになっています。

小さい数値 (4,000 や 5,000 など) では問題なく動作します。4,000,000 などのより大きな数では、ほぼ常に segfault でクラッシュします。その間の数字では、走るか走らないかで当たり外れがあります。

4

7 に答える 7

10
int primes[max];

prime = primes;
while(*prime) {
    *prime = 0;
    prime++;    
}

前のコードでは、メモリをランダムに簡単に実行できます。基本的に、0 が見つかるまで RAM を使用しています。配列に 0 がない場合は、プロセスに属していないメモリに実行され、セグメンテーション違反が発生します。

編集:Alconが指摘したように、コードの他の場所でもこれを行っています。

また、利用可能なスタックメモリがそれほど多くない可能性があるため、スタックに素数を割り当てないことをお勧めします。

これを修正するには、代わりに次のコードを試してください

int primes = new int[max];

size_t count = 0;
while( count < max ) 
{
    prime[count] = 0;
    count++;    
}

そして、delete[] プライムを呼び出すことを忘れないでください。コードの最後 (素数配列の処理が終了したとき)

于 2009-08-22T21:57:00.083 に答える
1

スタックに配列を割り当てています。スタックのサイズには制限があり、オーバーフローする可能性があります。

new/delete を使用して配列を割り当ててみてください。

于 2009-08-22T21:56:04.797 に答える
1

まず、これには問題があります。

int sum_array(int num_array[]) {
    int current_total = 0;
    int *iptr = num_array;
    while(*iptr) {
        current_total += *iptr;
        iptr++;
    }
    return current_total;
}

これが言うことは、与えられた配列の先頭から開始することです。int のサイズのメモリ ブロックの値がゼロでない間、次のメモリ ブロックに移動します。ここで何が起こるかというと、配列の末尾を超えて進み続け、最終的にメモリをいじってはいけません。これがセグメンテーション フォールトの原因です。ランダムに見える理由は、配列の末尾のメモリが空である場合があり、これで問題なく動作するからです。しかし、そうでない場合もあり、アクセスしてはならないメモリにアクセスしてクラッシュします。

それが唯一の問題ではないかもしれませんが、私が最初に気づいた問題でした。これを修正するには、配列のサイズを追跡し、それを関数に渡し、ポインタを使用するのではなく、for ループを使用して反復します。このような:

int sum_array(int num_array[], int arraySize) {
    int current_total = 0;
    for(int i = 0; i < arraySize; i++) {
        current_total += num_array[i];
    }
    return current_total;
}

また何かないか探してみます。

編集:

もう一度見てみると、他の 2 つの場所で同じことを行っています。ここ:

while(*prime) {
        cout << *prime << " ";
        prime++;
    }

そしてここ:

while(*prime) {
    *prime = 0;
    prime++;    
}

どちらの場所でも、アレイをオーバーランしているドーナツにドルを賭けます。それがセグメンテーション違反の原因です。あなたが初めての場合は、ポインター演算を使用して配列をトラバースしないことを強くお勧めします。古き良き for ループに固執し、for ループの最後を追跡します。

他の人々は、スタックの代わりにヒープから配列を割り当てることを提案しています。これは巨大な配列の場合は良い考えですが、少なくとも私の経験では、スタック オーバーランが通常セグメンテーション違反を引き起こすことはありません。通常、スタック内よりも多くのスペースを割り当てると、コンパイラはそれを認識します。それでも、ベクトルを使用することをお勧めします (宿題に大きなクレジットを追加するには、ヒープからポインターの配列として割り当てられた二重ポインターを使用して独自のベクトルを実装する方法を理解できるかどうかを確認してください;)) または単に std を使用します。 :ベクター。これは拡張可能な配列であり、必ずしも必要ではない大量のスペースを割り当てるのではなく、見つけたときに配列に素数を追加できます。

于 2009-08-22T21:56:50.850 に答える
1

素数の配列を動的に割り当てる必要がありますprimes。つまり、次のようになります。

int* primes = new int[max];

あなたのプログラムはそのままコンパイルするべきではありません。宿題頑張ってください!

于 2009-08-22T21:58:15.997 に答える
1

他の人 (Goz など) は正しい答えを提供しています。初期化されていない変数の値は、実行ごとに異なるため、信頼できません。他の人が指摘しているように、通常、スタック領域はヒープ領域よりも不足しているため、スタックに大きな配列を割り当てることも危険です。

副次的な問題として、現在の方法で可変サイズの配列を割り当てることは、primes[max]標準に準拠した C++ ではなく、g++ 拡張であるため、現状のコードは他のコンパイラでは機能しそうにありません。代わりにnewandを使用することもできますが、これらの状況で使用する習慣を身につけたほうがよいでしょう。deletevector<int>

[編集: トラブルの本当の根本原因が別のところにあることを指摘してくれてありがとう。]

于 2009-08-22T22:01:06.130 に答える
1

Goz は、物事がいかに早い段階でうまくいかなくなるかを指摘しています。

初心者は間違いやすいですが、ベテランでも全く同じ間違いをします。このため、退役軍人は問題を自動的に検出するための優れたプログラムを作成しました。

無料のプログラムには、コードを実行する前に検査するlintや、実行時にコードを検査するvalgrindなどがあります。Windows では、 Purifyのような他の商用の代替手段があります。

開発中に valgrind や静的コード チェッカーを使用してプログラムを実行すること、およびコンパイラからすべての警告を有効にしてコンパイルすることは、経験豊富なベテランにとっても開発衛生の一部です。

于 2009-08-22T22:07:44.260 に答える
0
int primes[max];

スタックはデフォルトで小さいサイズであるため、スタックに巨大な配列を割り当てることは良くありません。ヒープに素数[]を割り当てる方が良いです。

于 2009-08-22T21:56:26.763 に答える