阵列的随机元素:基于堆栈的缓冲区溢出错误

时间:2017-07-02 07:45:04

标签: c++ buffer-overrun

我给出的代码是原始程序的问题部分。它随机地交换myArray的两个元素N次和T个循环。该程序按照预期的方式完成,但在击中"返回0"它显示错误按摩" program.exe已停止工作"。调试输出显示

Stack cookie instrumentation code detected a stack-based buffer overrun

为什么程序在完成工作后显示错误? 我该如何解决这个问题?

#include <iostream>
#include <ctime>    
#include <cstdlib>

using namespace std;

int main()
{
    const int N = 10000;
    const int T = 100; 

    srand((unsigned)time(0));   

    bool myArray[N] ;
    bool temp = true;
    int save1 = 0;
    int save2 = 0;

    //initializing myArray
    for (int index = 0; index < N/2; index++) {
        myArray[index] = false;
    }
    for (int index = N/2; index < N; index++) {
        myArray[index] = true;
    }

    for (int index = 0; index < T; index++) {

        for (int index1 = 0; index1 < N; index1++) {    
            save1 = int( N*rand()/RAND_MAX );
            save2 = int( N*rand()/RAND_MAX );


            temp = myArray[save1];
            myArray[save1] = myArray[save2] ;
            myArray[save2] = temp; 
        }
    }

    cout<<" Press any key to exit...";
    cin.get();

    return 0;
}

编辑: 我必须生成从0到(N-1)的随机整数。在myArray中调用第N个位置就是在创建问题。

但以下方法均未均匀生成随机整数。

    save1 = int( (N-1)*rand()/RAND_MAX );

,也不

    save1 = int( N*rand()/(RAND_MAX+1) );

这个方法的问题有一个很好的video。 Mic和Bob__指出,(N-1)*rand()引起的问题也超出了问题。

对于大范围的随机整数,此模数方法也非常低效(有关详细信息,请查看此article)。因此,我生成统一随机数的最佳机会是以下方法(从文章中借用)。

while(true)
{
  int value = rand();
  if (value < RAND_MAX - RAND_MAX % range)
    return value % range;
}

同样,为了改组数组元素,最好使用random_shuffle函数或Fisher–Yates shuffle以获得最佳性能。

3 个答案:

答案 0 :(得分:0)

至少要修理一件事:

rand()返回0到RAND_MAX之间的随机整数,因此必须替换

  N*rand()/RAND_MAX 

通过

  N*rand()/(1+RAND_MAX)

答案 1 :(得分:0)

您应该将N替换为(N-1)。可能这就是你想要做的事情。

    save1 = int( (N-1)*rand()/RAND_MAX );
    save2 = int( (N-1)*rand()/RAND_MAX );

只是想知道你的意图是否要使用`Index1&#39;在语句中计算save1&amp; SAVE2。这也将解决问题。

答案 2 :(得分:0)

让我们考虑这一行(已编辑的qustion):

save1 = int( (N-1)*rand()/RAND_MAX );

save1int类型的变量,N是相同类型的const,而rand()返回范围为[0}的int ,RAND_MAX]。

在C ++中,这个表达式从左到右进行计算,所以首先是乘法,然后是除法。 如果rand()返回的值大于INT_MAX /(N - 1),则此操作会溢出,从而导致未定义的行为。在大多数实现中,由于积分值的二进制补码表示,结果可以是负值。

之后,执行RAND_MAX的整数除法,以便对于任何值x,使得-RAND_MAX&lt; x&lt; RAND_MAX结果为0。

您可以看到here您的程序(我只添加了一行来证明我的观点)编译并执行。请注意indeces不为零的次数。

C中使用rand()生成0到N(不包括)之间随机数的常用方法是:

int number = rand() % N;

考虑一个更好的算法来重新排列一个数组,比如Fisher Yates,你可以在C中实现:

void my_c_shuffle(bool *arr, size_t n)
{
    while ( n > 1 )
    {
        size_t choice = rand() % n;
        --n;
        bool temp = arr[n];
        arr[n] = arr[choice];
        arr[choice] = temp;
    }
}

在C ++中,您应该使用标准库而不是重写这些算法:

#include <iostream>
#include <random>
#include <array>
#include <algorithm>

int main()
{
    std::random_device rd;
    std::mt19937 g(rd());

    std::array<bool, 10000> my_array;
    auto middle = my_array.begin() + my_array.size() / 2;
    std::fill(my_array.begin(), middle, false);
    std::fill(middle, my_array.end(), true);

    std::shuffle(my_array.begin(), my_array.end(), g);  
}