看似无关的代码更改会产生不同的结果

时间:2013-03-08 23:20:51

标签: c++ g++

gnu编译器,从命令行运行,使用没有mod的sublime文本。

简单程序,用于显示递归函数的运行时间,该函数采用5000索引数组,在0和1之间具有均匀分布的随机数,并添加它们(意味着您应该在2500的球场中得到一个值)。下面的代码始终正常工作,并产生合理接近预期值的东西。但是,在其中一个couts中添加一个新的行/标签,一切都在手提篮中下地狱(见下文)。

#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.15 x 10 ^ 257。没有进行任何其他更改,即使经过数十次运行,这些数字也非常典型,您在上面看到的代码是编译和运行的确切代码。

2 个答案:

答案 0 :(得分:3)

您在这里有一个越界访问权限:

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

这会在您的计划中注入 Undefined Behavior 。当您的程序具有未定义的行为时,一切都会发生,包括有时程序seems to run just fine

答案 1 :(得分:0)

你正在阅读无效记忆(arrayToFill[lengthOfArray])。这是未定义的行为,因此它变得棘手。也许你碰巧碰到了控制台的记忆,谁知道。无论确切原因是什么,这都不是编译器中的错误。这是你代码中的一个错误。

更新

要提供更多详细信息,因为array是堆栈中的最后一项,超出它的内存通常会在应用程序启动时未使用并进行零初始化(操作系统为保证安全;确保您可以例如,不要读取其他程序可能留下的任何旧密码。

但是如果调用另一个具有局部变量的函数,它将在该空间中放置一个值(它不会被清除;你永远不应该访问它,操作系统不在乎你是否读过您自己的密码)。

可能是cout的<<运算符有一些内部条件,有时会将它的第一个局部变量设置为非零值。也许第一个变量是bool beganWithNewline(设计!),它将您读取的元素的第一个字节设置为1,但因为它是双精度的最重要的字节,所以它会产生巨大的价值(ok所以它也必须在小数部分设置一些东西但是你看到了这一点。