在C++中如何生成随机字符串?

13

我正在寻找在C++中生成随机字符串的方法。这是我的代码:

string randomStrGen(int length) {
    static string charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
    string result;
    result.resize(length);

    srand(time(NULL));
    for (int i = 0; i < length; i++)
        result[i] = charset[rand() % charset.length()];

    return result;
}

但是 seed(time(NULL)) 不够随机。在C++中有没有其他更好的方法来生成随机字符串?


5
可以,请问“not random enough”是什么意思? 不够随机。 - Bobby
@Bobby:这是因为我错误地使用了srand,如果在短时间内调用函数,则生成的随机字符串将相同。 - Jichao
不够随机,你可以使用 sleep(1)。但自然而然,这是一个非常糟糕的想法,因为很明显你不能等待太久。但尽管如此,这仍然是一个想法。 - Tebe
6个回答

26
不要在每个函数调用中调用srand() - 只在第一个函数调用或程序启动时调用一次。您可能希望有一个指示是否已经调用srand()的标志。
建议的方法不错,只是您误用了srand()并得到了可预测的糟糕结果。

3
+1 很棒的答案。这样一个标志的问题在于,需要使用不同标志的其他需要随机数的函数也会导致问题。我认为最好的方法是让需要随机数的函数获得随机数,并且与生成器初始化分离开来。实际上,在main的顶部进行种子初始化即可。 :-) - C. K. Young
或者使用具有自己种子的可重入版本。 - fa.
@fa: True表示这会防止生成器之间相互干扰,但是如果这些不同的函数最初都运行得太接近,你仍然会遇到同样的问题。 - C. K. Young
重复使用种子值是一个不好的主意。如果你必须构建自己的rand函数并在第一次通过时调用srand()(返回rand()的结果)。 - Martin York

1

你可以使用Boost.Random。它使用的是与大多数标准库提供的不同生成器,应该更加健壮。

具体来说,大多数标准库提供线性同余生成器,当你用小数字mod它们的结果时,它们的表现并不好。Boost.Random有一个Mersenne扭曲生成器。

正如sharptooth所说(很好的发现!),只在程序的最开始种子化生成器一次。每次想要随机数时都进行种子化是适得其反的。


3
仅仅在每次调用时进行种子设置不仅是适得其反的,如果该函数在没有足够长的延迟情况下被重复调用,它会产生相同的结果。 - sharptooth
没错。实际上,最好的做法是让库在这方面像Perl一样自行初始化(当然要使用合理的种子),如果程序本身没有这样做的话。我的意思是,现在为时已晚了,因为标准C库不能在不违反标准的情况下这样做,但你知道我的意思。 :-) - C. K. Young

1
创建一个接口来获取此网站http://www.random.org/中的随机数,您将确保获得真正的随机数!但是,如果您正在寻求性能...

0
使用std::generate_n。这样你可以指定生成字符串的长度。在下面的例子中,它是4。
std::string uniqueName() {
    auto randchar = []() -> char
    {
        const char charset[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
        const size_t max_index = (sizeof(charset) - 1);
        return charset[ rand() % max_index ];
    };
    std::string str(4,0);
    std::generate_n( str.begin(), 4, randchar );
    return str;
}

0
如果您喜欢使用标准库,那么您可以像这样做:
<somewhere else>
srand(NULL);
</somewhere else>

char get_rand_char() {
  static string charset(...);
  return charset[rand() % charset.size()];
}

std::string generate_random_string(size_t n) {
  char rbuf[n];
  std::generate(rbuf, rbuf+n, &get_rand_char);
  return std::string(rbuf, n);
}

这段代码自然更加模块化,标准库维护者往往编写比我更好的代码。这样我就可以在不触及其他任何部分的情况下更改代码中生成随机字符的部分。我甚至可以将其转发到一个随机选择随机数生成器的函数!虽然这并不会增加随机性或其他什么...


0

在Unix系统中,您可以从文件/dev/random读取随机值。


2
除非您将数字用于加密目的,否则直接从/dev/random读取数字(除了用作另一个PRNG的种子之外)是浪费的。 - C. K. Young

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接