繁体   English   中英

数组的重排元素:基于堆栈的缓冲区溢出错误

[英]Shuffling elements of Array : stack-based buffer overrun error

我给定的代码是原始程序的问题部分。 它将N次随机交换myArray的两个元素,并进行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) );

关于此方法的问题,有一个很好的视频 正如Mic和Bob__指出的那样,还有(N-1)*rand()引起的超限问题。

对于较大范围的随机整数,这种取模方法也非常无效(请查看本文以了解详细信息)。 因此,生成统一随机数的最佳机会是以下方法(从本文中借用)。

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

同样对于混洗数组元素,最好使用random_shuffle函数或Fisher–Yates shuffle以获得最佳性能。

至少要解决的一件事:

rand()返回介于0和RAND_MAX(含)之间的随机整数,因此您必须替换

  N*rand()/RAND_MAX 

通过

  N*rand()/(1+RAND_MAX)

您应将N替换为(N-1) 大概就是您想要的。

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

只是想知道您是否打算在语句中使用“ Index1”来计算save1和save2。 那也将解决问题。

让我们考虑一下(已编辑的问题的)这一行:

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

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

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

之后,执行RAND_MAX的整数除法,以便对于-RAND_MAX <x <RAND_MAX的任何值x,结果均为0。

您可以在此处看到您的程序(我只添加了一行来证明我的观点)已编译并执行。 请注意,索引的次数不为零。

在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);  
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM