简体   繁体   中英

Shuffling elements of Array : stack-based buffer overrun error

My given code is the problem part of the original program. It swaps two elements of myArray randomly N times and in T number of loops. The program does what it is supposed to but after hitting "return 0" it shows error massage of "program.exe has stopped working". The debug output shows

Stack cookie instrumentation code detected a stack-based buffer overrun

Why the program is showing error after its job is done? How can I fix this ?

#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;
}

EDIT: I had to generate random integer from 0 to (N-1). Calling Nth location in myArray was creating the problem.

But neither of the following methods generates random integer uniformly.

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

nor

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

There is a nice video on the problem of this method. There is also the problem of overrun caused by (N-1)*rand() as Mic and Bob__ pointed out.

This modulo method is also very inefficient for large range of random integer (check this article for details). So, my best chance of generating uniform random numbers is the following method (borrowed from the article).

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

Also for shuffling array elements it is best to use random_shuffle function or Fisher–Yates shuffle for optimum performance.

At least one thing to fix:

rand() returns a random integer between 0 and RAND_MAX inclusive, thus you must replace

  N*rand()/RAND_MAX 

by

  N*rand()/(1+RAND_MAX)

You should replace N with (N-1) . Probably that's what you want to do.

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

Just wondering if your intention is to use `Index1' in statements to calculate save1 & save2. That will fix issue too.

Let's consider this line (of the edited qustion):

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

Where save1 is a variable of type int , N is a const of the same type and rand() returns an int in the range [0, RAND_MAX].

In C++ this expression is evaluated left to right, so first the multiplication, then the division. If rand() returns a value greater then INT_MAX / (N - 1), this operation overflows causing Undefined Behavior. In most implementations, due to two's complement representation of integral values, the result can be a negative value.

After that, an integer division by RAND_MAX is performed, so that for any value x such that -RAND_MAX < x < RAND_MAX the result is 0.

You can see here that your program (I only added a line to prove my point) compiles and executes. Please note how many times the indeces are not zero.

A common way in C, using rand() , to generate a random number between 0 and N (excluded) is:

int number = rand() % N;

Consider also a better algorithm to shuffle an array, like Fisher Yates , that you could implement in C as:

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

In C++ you should use the Standard Library instead of rewriting those algorithms:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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