簡體   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