洗牌 Array 的元素:基于堆栈的缓冲区溢出错误
Shuffling elements of Array : stack-based buffer overrun error
我给出的代码是原程序的问题部分。它在 T 次循环中随机交换 myArray 的两个元素 N 次。该程序执行了它应该执行的操作,但在点击 "return 0" 后,它显示 "program.exe has stopped working" 的错误信息。调试输出显示
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
以获得最佳性能。
至少要解决一件事:
rand() returns 介于 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 );
其中save1
是int
类型的变量,N
是相同类型的常量,rand()
returns是int
范围 [0, RAND_MAX].
在 C++ 中,此表达式是从左到右求值的,因此首先是乘法,然后是除法。
如果 rand()
returns 大于 INT_MAX / (N - 1) 的值,此操作会溢出导致未定义的行为。在大多数实现中,由于整数值的二进制补码表示,结果可能是负值。
之后,执行 整数 除以 RAND_MAX,因此对于满足 -RAND_MAX < x < [=41 的任何值 x =] 结果为 0.
你可以看到here你的程序(我只加了一行来证明我的观点)编译并执行了。请注意索引不为零的次数。
在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);
}
我给出的代码是原程序的问题部分。它在 T 次循环中随机交换 myArray 的两个元素 N 次。该程序执行了它应该执行的操作,但在点击 "return 0" 后,它显示 "program.exe has stopped working" 的错误信息。调试输出显示
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
以获得最佳性能。
至少要解决一件事:
rand() returns 介于 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 );
其中save1
是int
类型的变量,N
是相同类型的常量,rand()
returns是int
范围 [0, RAND_MAX].
在 C++ 中,此表达式是从左到右求值的,因此首先是乘法,然后是除法。
如果 rand()
returns 大于 INT_MAX / (N - 1) 的值,此操作会溢出导致未定义的行为。在大多数实现中,由于整数值的二进制补码表示,结果可能是负值。
之后,执行 整数 除以 RAND_MAX,因此对于满足 -RAND_MAX < x < [=41 的任何值 x =] 结果为 0.
你可以看到here你的程序(我只加了一行来证明我的观点)编译并执行了。请注意索引不为零的次数。
在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);
}