选择 4 个随机数 printf
Choose 4 randoms printf
所以,我的代码有问题。程序需要从4个printfs中随机选择一个打印在终端。我是新手,很抱歉。
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
int main () {
setlocale (LC_ALL, "Portuguese");
int opcao;
opcao = rand() % 3 + 1;
if (opcao == 0) {
printf ("\nA opção sorteada foi a de que o 1º classificado atual será o campeão (FC Porto)");
}
if (opcao == 1) {
printf ("\nA opção sorteada foi a de que o 1º classificado na 1ª volta será o campeão (SL Benfica)");
}
if (opcao == 2) {
printf ("\nA opção sorteada foi a de que Porto e Benfica farão um jogo em campo neutro para determinar o campeão!");
}
if (opcao == 4) {
printf ("\nFoi sorteada a opção de que não haverá campeão esta época");
}
return 0;
}
这是我的代码,但始终只选择相同的 printf。
您没有为随机数生成器提供种子。从 man
页面,
If no seed value is provided, the functions are automatically seeded
with a value of 1.
如果您在每个 运行 上都有相同的种子,您将始终获得相同的随机序列。
你的程序有几个问题:
- 您没有种子,这就是重复数字的原因。使用
srand (time(NULL)); // #include <time.h>
使用前 rand()
你的随机数没有排序,你有0-2
然后4
,当你得到3
时没有可用的选项。如果是故意的,请忽略此评论。
如果使用 rand() % 3 + 1;
,您的随机数的范围将从 1
到 3
,因此 opcao == 0
和 opcao == 4
永远不会出现。对于 0-4
间隔,您将需要类似的内容:
opcao = rand() % 5;
我想在这里补充一些东西,添加到以前的答案中。
首先,您不是在为自己编写代码。作为一个非英语母语的人,我理解为什么用你的母语写下代码似乎更容易,但不要这样做!
其次,我对代码进行了更改,以使其更容易阅读:
#include <time.h>
#include <cstdint>
#include <iostream>
#include <string>
constexpr uint32_t NUM_OF_POSSIBLE_PROMPTS = 4;
int main () {
srand(time(NULL)); // seed according to current time
for (uint32_t i = 0; i < 10; ++i)
{
int option = rand() % (NUM_OF_POSSIBLE_PROMPTS);
std::string prompt = "";
switch (option)
{
case 0:
prompt = "option 0";
break;
case 1:
prompt = "option 1";
break;
case 2:
prompt = "option 2";
break;
case 3:
prompt = "option 3";
break;
default:
// some error handling!
break;
}
std::cout << prompt << std::endl;
}
return 0;
}
我使用的是 switch-case
而不是 if-else-if-else
,后者更具可读性并且 高效 !
我正在使用 constexpr
来存储我的 硬编码 号码 - 在代码中使用硬编码号码是一个坏习惯(在实际程序中,我也会将循环边界的 constexpr 值设置为 10)。
在 c++ 中(与 c 不同),我们使用 std::cout 及其运算符 << 来打印,而不是 printf 函数。它与其他类型的流进行了统一的行为,例如 stringstream(这在尝试实时构造字符串时很有用,但是,它对资源有些沉重!)。
由于此代码更有条理,您更容易理解可能发生错误的位置,并且从一开始就不太可能发生错误。
例如,使用 gcc 的 -Wswitch-enum 标志将确保如果您使用枚举,则所有值都必须在 switch-case
部分中处理(当然,这使您的程序更不容易出错)。
P.S, 我添加循环只是为了告诉你这段代码每一轮都会得到不同的结果,你可以通过 运行 代码多次测试.
使用 <random>
library instead of the obsolete and error-prone std::rand
(using the modulo operator to obtain a random integer in a range is ). See 获取更多信息。
#include <iostream>
#include <random>
int main()
{
std::mt19937 engine{std::random_device{}()};
std::uniform_int_distribution<int> dist{0, 3};
switch (dist(eng)) {
case 0:
std::cout << "...\n";
break;
case 1:
std::cout << "...\n";
break;
case 2:
std::cout << "...\n";
break;
case 3:
std::cout << "...\n";
break;
}
}
在这里,我们首先创建一个std::mt19937
engine, which produces uniformly distributed integers in the half-open range [0, 232), and seed it using a std::random_device
, which is supposed to generate a non-deterministic number (it may be implemented using the system time, for example). Then, we create a std::uniform_int_distribution
,通过将引擎作为参数调用它,将引擎生成的随机数映射到包含区间[0, 3]中的整数。
这可以通过打印一系列字符串来概括:
template <typename RanIt, typename F>
decltype(auto) select(RanIt begin, RanIt end, F&& f)
{
if (begin == end) {
throw std::invalid_argument{"..."};
}
thread_local std::mt19937 engine{std::random_device{}()};
using index_t = long long; // for portability
std::uniforn_int_distribution<index_t> dist{0, index_t{end - begin - 1}};
return std::invoke(std::forward<F>(f), begin[dist(engine)]);
}
int main()
{
const std::array<std::string, 4> messages {
// ...
};
select(messages.begin(), messages.end(),
[](const auto& string) {
std::cout << string << '\n';
});
}
这里,我们取a pair of random access iterators and a Callable object支持从任意随机可访问范围中选择一个元素,并对其进行任意操作。
然后,我们创建一个std::mt19937
引擎即thread_local
(that is, each thread has its own engine) to prevent data races。引擎的状态在调用之间保持不变,因此我们只为每个线程播种一次。
之后,我们创建一个std::uniform_int_distribution
来生成随机索引。请注意,我们使用 long long
而不是 typename std::iterator_traits<RanIt>::difference_type
: std::uniform_int_distribution
is only guaranteed to work with short
, int
, long
, long long
, unsigned short
, unsigned int
, unsigned long
, and unsigned long long
, so if difference_type
is signed char
or an extended signed integer type, it results in undefined behavior. long long
is the largest supported signed integer type, and we use braced initialization to prevent narrowing conversions。
最后,我们std::forward
the Callable object and std::invoke
it with the selected element. The decltype(auto)
specifier makes sure that the type and value category的调用被保留了。
我们使用打印所选元素的 std::array
and a lambda expression 调用该函数。
从C++20开始,我们可以使用概念来约束函数模板:
template <std::random_access_iterator RanIt,
std::indirectly_unary_invocable<RanIt> F>
decltype(auto) select(RanIt begin, RanIt end, F&& f)
{
// ...
}
在C++20之前,我们也可以使用SFINAE:
template <typename RanIt, typename F>
std::enable_if_t<
std::is_base_of_v<
std::random_access_iterator_tag,
typename std::iterator_traits<RanIt>::iterator_category
>,
std::invoke_result_t<F, typename std::iterator_traits<RanIt>::value_type>
> select(RanIt begin, RanIt end, F&& f)
{
// ...
}
所以,我的代码有问题。程序需要从4个printfs中随机选择一个打印在终端。我是新手,很抱歉。
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
int main () {
setlocale (LC_ALL, "Portuguese");
int opcao;
opcao = rand() % 3 + 1;
if (opcao == 0) {
printf ("\nA opção sorteada foi a de que o 1º classificado atual será o campeão (FC Porto)");
}
if (opcao == 1) {
printf ("\nA opção sorteada foi a de que o 1º classificado na 1ª volta será o campeão (SL Benfica)");
}
if (opcao == 2) {
printf ("\nA opção sorteada foi a de que Porto e Benfica farão um jogo em campo neutro para determinar o campeão!");
}
if (opcao == 4) {
printf ("\nFoi sorteada a opção de que não haverá campeão esta época");
}
return 0;
}
这是我的代码,但始终只选择相同的 printf。
您没有为随机数生成器提供种子。从 man
页面,
If no seed value is provided, the functions are automatically seeded with a value of 1.
如果您在每个 运行 上都有相同的种子,您将始终获得相同的随机序列。
你的程序有几个问题:
- 您没有种子,这就是重复数字的原因。使用
srand (time(NULL)); // #include <time.h>
使用前 rand()
你的随机数没有排序,你有
0-2
然后4
,当你得到3
时没有可用的选项。如果是故意的,请忽略此评论。如果使用
rand() % 3 + 1;
,您的随机数的范围将从1
到3
,因此opcao == 0
和opcao == 4
永远不会出现。对于0-4
间隔,您将需要类似的内容:
opcao = rand() % 5;
我想在这里补充一些东西,添加到以前的答案中。
首先,您不是在为自己编写代码。作为一个非英语母语的人,我理解为什么用你的母语写下代码似乎更容易,但不要这样做!
其次,我对代码进行了更改,以使其更容易阅读:
#include <time.h>
#include <cstdint>
#include <iostream>
#include <string>
constexpr uint32_t NUM_OF_POSSIBLE_PROMPTS = 4;
int main () {
srand(time(NULL)); // seed according to current time
for (uint32_t i = 0; i < 10; ++i)
{
int option = rand() % (NUM_OF_POSSIBLE_PROMPTS);
std::string prompt = "";
switch (option)
{
case 0:
prompt = "option 0";
break;
case 1:
prompt = "option 1";
break;
case 2:
prompt = "option 2";
break;
case 3:
prompt = "option 3";
break;
default:
// some error handling!
break;
}
std::cout << prompt << std::endl;
}
return 0;
}
我使用的是
switch-case
而不是if-else-if-else
,后者更具可读性并且 高效 !我正在使用
constexpr
来存储我的 硬编码 号码 - 在代码中使用硬编码号码是一个坏习惯(在实际程序中,我也会将循环边界的 constexpr 值设置为 10)。在 c++ 中(与 c 不同),我们使用 std::cout 及其运算符 << 来打印,而不是 printf 函数。它与其他类型的流进行了统一的行为,例如 stringstream(这在尝试实时构造字符串时很有用,但是,它对资源有些沉重!)。
由于此代码更有条理,您更容易理解可能发生错误的位置,并且从一开始就不太可能发生错误。
例如,使用 gcc 的 -Wswitch-enum 标志将确保如果您使用枚举,则所有值都必须在 switch-case
部分中处理(当然,这使您的程序更不容易出错)。
P.S, 我添加循环只是为了告诉你这段代码每一轮都会得到不同的结果,你可以通过 运行 代码多次测试.
使用 <random>
library instead of the obsolete and error-prone std::rand
(using the modulo operator to obtain a random integer in a range is
#include <iostream>
#include <random>
int main()
{
std::mt19937 engine{std::random_device{}()};
std::uniform_int_distribution<int> dist{0, 3};
switch (dist(eng)) {
case 0:
std::cout << "...\n";
break;
case 1:
std::cout << "...\n";
break;
case 2:
std::cout << "...\n";
break;
case 3:
std::cout << "...\n";
break;
}
}
在这里,我们首先创建一个std::mt19937
engine, which produces uniformly distributed integers in the half-open range [0, 232), and seed it using a std::random_device
, which is supposed to generate a non-deterministic number (it may be implemented using the system time, for example). Then, we create a std::uniform_int_distribution
,通过将引擎作为参数调用它,将引擎生成的随机数映射到包含区间[0, 3]中的整数。
这可以通过打印一系列字符串来概括:
template <typename RanIt, typename F>
decltype(auto) select(RanIt begin, RanIt end, F&& f)
{
if (begin == end) {
throw std::invalid_argument{"..."};
}
thread_local std::mt19937 engine{std::random_device{}()};
using index_t = long long; // for portability
std::uniforn_int_distribution<index_t> dist{0, index_t{end - begin - 1}};
return std::invoke(std::forward<F>(f), begin[dist(engine)]);
}
int main()
{
const std::array<std::string, 4> messages {
// ...
};
select(messages.begin(), messages.end(),
[](const auto& string) {
std::cout << string << '\n';
});
}
这里,我们取a pair of random access iterators and a Callable object支持从任意随机可访问范围中选择一个元素,并对其进行任意操作。
然后,我们创建一个
std::mt19937
引擎即thread_local
(that is, each thread has its own engine) to prevent data races。引擎的状态在调用之间保持不变,因此我们只为每个线程播种一次。之后,我们创建一个
std::uniform_int_distribution
来生成随机索引。请注意,我们使用long long
而不是typename std::iterator_traits<RanIt>::difference_type
:std::uniform_int_distribution
is only guaranteed to work withshort
,int
,long
,long long
,unsigned short
,unsigned int
,unsigned long
, andunsigned long long
, so ifdifference_type
issigned char
or an extended signed integer type, it results in undefined behavior.long long
is the largest supported signed integer type, and we use braced initialization to prevent narrowing conversions。最后,我们
std::forward
the Callable object andstd::invoke
it with the selected element. Thedecltype(auto)
specifier makes sure that the type and value category的调用被保留了。
我们使用打印所选元素的 std::array
and a lambda expression 调用该函数。
从C++20开始,我们可以使用概念来约束函数模板:
template <std::random_access_iterator RanIt,
std::indirectly_unary_invocable<RanIt> F>
decltype(auto) select(RanIt begin, RanIt end, F&& f)
{
// ...
}
在C++20之前,我们也可以使用SFINAE:
template <typename RanIt, typename F>
std::enable_if_t<
std::is_base_of_v<
std::random_access_iterator_tag,
typename std::iterator_traits<RanIt>::iterator_category
>,
std::invoke_result_t<F, typename std::iterator_traits<RanIt>::value_type>
> select(RanIt begin, RanIt end, F&& f)
{
// ...
}