【问题标题】:generate random numbers and put them in an array生成随机数并将它们放入数组中
【发布时间】:2018-09-19 18:35:15
【问题描述】:

我正在寻找用 C++ 编写一个名为 Farkle 的小骰子游戏(你可能从 Kingdom come delivarance 知道它),但我还在学习,所以我遇到了一些麻烦。 atm 我正在尝试掷 6 个骰子并将每个掷出的数字放入一个数组中,以便之后能够使用它。一切似乎都正常,但 Visual Studio 正在输出此错误代码:

运行时检查失败 #2 - 变量“die”周围的堆栈已损坏。

这是我的代码:

#include "stdafx.h"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

using namespace std;


void dice() {
    int die[5];
    int i = 1;
    while (i <= 6) {
        die[i] = rand() % 6 + 1;
        cout << die[i];
        i++;
    }
}


int main()
{
    srand(time(NULL));
    dice();
    system("STOP");
    return 0;
}

这实际上是这种程序的正确方法吗?

【问题讨论】:

  • int die[5].您认为您可以访问哪些索引?
  • 大小为 N 的数组的索引从 0 到 N-1,如果 int die[N] 则循环将是 (for int i = 0; i
  • 您正在使用模数 (%) 引入偏差。最好使用std::uniform_int_distribition。还; rand() 生成质量很差的随机数,更好的选择是std::mt19937,至于播种,最好使用std::random_device。
  • 虽然@ArkadyGodlin 只是为了解释,但在给定的情况下,您实际上应该更喜欢 for 循环,原因如下:1. i 的范围仅限于循环体(因为您不需要它之后无论如何)2.更紧凑,条件检查和值修改紧密结合在一起,因此您可以获得更好的可读性。

标签: c++ arrays random dice


【解决方案1】:

试试这个代码:

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

void populateArray( int ar[], /*const*/ int n )
{
    for( int i = 0 ; i < n ; ++i ) ar[i] = std::rand() % 50 + 1 ;
}

int main()
{
    // http://en.cppreference.com/w/cpp/numeric/random/srand
    std::srand( std::time(nullptr) ) ; // **** important ****

    const int ARRAY_SIZE = 50;
    int ar[ARRAY_SIZE] = {0} ;

    populateArray( ar, ARRAY_SIZE ) ;

    for( int v : ar ) std::cout << v << ' ' ;
}

【讨论】:

    【解决方案2】:

    索引i 应该从0 到5,而不是从1 到6。 很明显i = 6的时候,跑出dice的范围就报错了。

    编辑这些行:

    int i = 0;
        while (i <= 5) {
            ....
    

    【讨论】:

    • int die[5]; -> 索引 5 也超出范围!
    • @Aconcagua 你是对的。我的错。也应该改变骰子[6]
    【解决方案3】:

    您的代码中有 2 个问题:

    1. 你的数组的大小是 5,但是你访问了 6 个索引(1 到 6),你可以通过将条件中的 &lt;= 更改为 &lt; 来避免这种情况。

    2. C++ 中数组的索引从 0 开始,但您从 1 开始。如果您将代码中的每个 die[i] 更改为 die[i-1],则可以解决此问题。

    另一种方法(解决这两个问题)是初始化 i=0 并使用 while (i &lt; 5)

    【讨论】:

    • “您可以通过将条件中的&lt;= 更改为&lt; 来避免这种情况”(&lt; 而不是=)
    • 当然。固定的。谢谢
    • “另一种方法” - 好吧,在特定情况下,这是首选方法。 die[i-1] 很好 i 的原始值,但需要用于其他目的,但这里不是这种情况......
    • 好吧,如果我编写这个代码,我肯定会使用第二个(或者很可能是 for 循环),但出于学习目的,第一个也演示(并解决)问题(甚至更好)
    • @OhadEytan 哦,对不起,我将它们视为单独的问题。最好的一行是显示正确解决方案的最后一行。
    【解决方案4】:

    不,生成均匀分布的随机数的更好方法是

    #include <random>
    #include <algorithm>
    
    std::random_device rd;  //Will be used to obtain a seed for the random number engine
    std::mt19937 gen(rd()); //Standard mersenne_twister_engine seeded with rd()
    std::uniform_int_distribution<> d6(1, 6); // {1, 2, 3, 4, 5, 6} with equal probability
    int die[5];
    std::generate(die, die + 5, [&gen, &d6](){ return d6(gen); });
    

    如果您要生成多组 5d6,您可以重复使用相同的 gen,而不是每次都重新初始化

    【讨论】:

    • 只是想知道,如果我们需要捕获gen,我们为什么不d6?
    • @Aconcagua 因为我没注意
    • 目前我只是为了学习目的而这样做,所以srand 似乎更容易一些,我不需要更多但我会考虑在何时实施我得到一切工作。谢谢
    • @BiBo 学习使用适当的工具比学习“看似简单”的工具要好。如果没有别的,我强烈建议使用std::generate
    • @Caleth 虽然你是对的,但我不想使用我不太理解的代码。一旦我掌握了基础知识,我会研究一下,我仍然需要更好地学习语法,因为我之前学过 Java。
    【解决方案5】:

    正如其他人指出的那样。您的错误源于使用的数组太小。这篇文章将更多地说明您的代码更像 C。

    在 C++ 中使用 std::array 代替原始数组更为惯用。

    还建议不要使用rand(),因为它会产生错误的随机数,并且通过使用模运算,您会为随机数引入额外的偏差。相反,应该使用 &lt;random&gt; 标头中的类。

    为了使代码更具可读性,您可以尝试使用 &lt;algorithm&gt; 中的函数来用命名算法替换循环。

    这导致以下代码:

    #include <algorithm>
    #include <array>
    #include <iostream>
    #include <iterator>
    #include <random>
    
    void dice() {
      std::array<int, 6> die;
      std::mt19937 gen{std::random_device{}()};
      std::uniform_int_distribution<int> dice_roll{1, 6};
      std::generate(begin(die), end(die), [&] { return dice_roll(gen); }); 
      std::copy(begin(die), end(die), std::ostream_iterator<int>{std::cout});
    }
    
    int main() {
      dice();
      std::cin.get();
    }
    

    【讨论】:

    • 很好,但对于我对 c++ 的理解来说只是一个一般性问题:为什么在这种情况下你可以使用例如begin 并且不必输入std::begin?
    • @JHBonarius die 会考虑 std:: 中的名称,因为它是 std::array。这称为Argument Dependant Lookup
    • @JHBonarius:当在某个命名空间a 中定义对象x 并在其上应用函数f f(x) 时,编译器将搜索f全局命名空间和a。正如@Caleth 所写,这称为参数依赖查找。
    猜你喜欢
    • 2020-07-16
    • 2012-05-27
    • 1970-01-01
    • 1970-01-01
    • 2017-04-17
    • 1970-01-01
    • 1970-01-01
    • 2017-08-07
    • 1970-01-01
    相关资源
    最近更新 更多