-7

gnuコンパイラ、コマンドラインから実行、modなしで崇高なテキスト2を使用。

0から1までの一様分布の乱数を含む5000インデックス配列を取得し、それらを追加する再帰関数の実行時間を表示する単純なプログラム(つまり、2500のボールパークのどこかで値を取得する必要があります)。以下のコードは一貫して正常に機能し、期待値にかなり近いものを生成します。ただし、カウトの1つに新しい行/タブを追加すると、すべてがハンドバスケットで地獄に落ちます(以下を参照)。

#include <iostream>
#include <stdlib.h>
#include <time.h>
using namespace std;

double sumOfRandomNumbers(double arrayToFill[], int lengthOfArray){
    if(lengthOfArray == 0) return arrayToFill[lengthOfArray];
    return arrayToFill[lengthOfArray] + sumOfRandomNumbers(arrayToFill, lengthOfArray - 1);
}

double seconds(){return double(clock())/CLOCKS_PER_SEC;}

int main(){

    int sizeOfArray = 5000;
    double sum = 0.0, deltaT = 0.0, array[sizeOfArray];
    srand(time(NULL));

    for(int i = 0; i < sizeOfArray; i++) array[i] = double(rand())/double(RAND_MAX);

    cout << "\nRecursive Method\n";
    deltaT = seconds();
    for (int i = 0; i < 100000; i++){
        sum = sumOfRandomNumbers(array, sizeOfArray);
        if (i%10000 == 0) cout << i/1000 << " percent complete\n";
    }
    deltaT = seconds() - deltaT;
    cout << "\n\n\t\tRecursive method found sum to be " << sum;
    cout << "\n\t\tThis recursive calc took " << deltaT << " seconds to run.\n";

}

出力

Recursive Method
0 percent complete
10 percent complete
20 percent complete
30 percent complete
40 percent complete
50 percent complete
60 percent complete
70 percent complete
80 percent complete
90 percent complete


                Recursive method found sum to be 2466.4
                This recursive calc took 12.226 seconds to run.

これは、コンパイルされたとおりの更新を含む更新されたコードです。奇妙な出力に注意してください。追加したコードを太字にしました。表示されない、または見づらい場合は、これが変更です

から

if (i%10000 == 0) cout << i/1000 << " percent complete\n";

if (i%10000 == 0) cout << "\n\t" << i/1000 << " percent complete\n";

.................................................。 ........................。

#include <iostream>
#include <stdlib.h>
#include <time.h>
using namespace std;

double sumOfRandomNumbers(double arrayToFill[], int lengthOfArray){
    if(lengthOfArray == 0) return arrayToFill[lengthOfArray];
    return arrayToFill[lengthOfArray] + sumOfRandomNumbers(arrayToFill, lengthOfArray - 1);
}

double seconds(){return double(clock())/CLOCKS_PER_SEC;}

int main(){

    int sizeOfArray = 5000;
    double sum = 0.0, deltaT = 0.0, array[sizeOfArray];
    srand(time(NULL));

    for(int i = 0; i < sizeOfArray; i++) array[i] = double(rand())/double(RAND_MAX);

    cout << "\nRecursive Method\n";
    deltaT = seconds();
    for (int i = 0; i < 100000; i++){
        sum = sumOfRandomNumbers(array, sizeOfArray);
        if (i%10000 == 0) cout << "\n\t" << i/1000 << " percent complete\n";
    }
    deltaT = seconds() - deltaT;
    cout << "\n\n\t\tRecursive method found sum to be " << sum;
    cout << "\n\t\tThis recursive calc took " << deltaT << " seconds to run.\n";

}

出力

Recursive Method

        0 percent complete

        10 percent complete

        20 percent complete

        30 percent complete

        40 percent complete

        50 percent complete

        60 percent complete

        70 percent complete

        80 percent complete

        90 percent complete


                Recursive method found sum to be 1.15021e+257
                This recursive calc took 12.262 seconds to run.

非常に合理的な2466.4から完全にばかげた1.15x10^257にどのように移行したかに注意してください。他の変更は行われていません。これらの数値は、数十回実行した後でも非常に一般的です。上記のコードは、コンパイルおよび実行された正確なコードです。

4

2 に答える 2

3

ここに境界外アクセスがあります:

double sumOfRandomNumbers(double arrayToFill[], int lengthOfArray){
    if (lengthOfArray == 0) return arrayToFill[lengthOfArray];
    //                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
    return arrayToFill[lengthOfArray] + 
    //     ^^^^^^^^^^^^^^^^^^^^^^^^^^
           sumOfRandomNumbers(arrayToFill, lengthOfArray - 1);
}

これにより、プログラムに未定義の動作が挿入されます。プログラムに未定義の動作がある場合、プログラムが正常に動作しているように見える場合を含め、すべてが発生する可能性があります

于 2013-03-08T23:25:34.283 に答える
0

空メモリ ( arrayToFill[lengthOfArray]) を読み込んでいます。これは未定義の動作であるため、おかしなことになります。たまたまコンソールのメモリにヒットしたのかもしれません。正確な理由が何であれ、これはコンパイラのバグではありません。それはあなたのコードのバグです。

アップデート:

詳細を説明すると、arrayはスタックの最後の項目であるため、それを超えるメモリは、アプリケーションの起動時に未使用でゼロ初期化されることがよくあります (オペレーティング システムがセキュリティのために行うことです。古いパスワードを読み取れないようにしてください。たとえば、別のプログラムによって残されています)。

しかし、ローカル変数を持つ別の関数が呼び出されると、そのスペースに値が入れられます (これはクリアされません。アクセスすることは想定されておらず、OS は自分のパスワードを読み取っても気にしません。 )。

cout の<<演算子には、最初のローカル変数をゼロ以外の値に設定する内部条件がある可能性があります。おそらく、最初の変数はbool beganWithNewline(不自然に!)、読み取った要素の最初のバイトを に設定していますが、1これは double の最上位バイトであるため、これは巨大な値になります (わかりましたので、分数部分ですが、要点がわかります)。

于 2013-03-08T23:27:14.563 に答える