srand无效?

程序在启动后,初始化的时候正确调用了srand(time(NULL)). 但是在之后使用的地方,rand() 得到的随机数序列,每次程序运行都是一致的。也就是srand()根本没起作用。更进一步调试,把srand注释掉,得到的随机数序列是一致的。这就奇怪了。
调了半天,没啥进展,跟进srand的实现看看:
void __cdecl srand (    unsigned int seed       )
{
        _getptd()->_holdrand = (unsigned long)seed;
}
这部分代码很简单,直接设置一下。问题是这个_getptd()是个什么东西。原来是个包装函数:
_ptiddata __cdecl _getptd (       void        ) 
{
        _ptiddata ptd = _getptd_noexit();
        if (!ptd) {
            _amsg_exit(_RT_THREAD); /* write message and die */
        }
        return ptd;
}

继续跟_getptd_noexit(),在这个函数里面,真相大白了。原来这个是获得当前thread相关的data指针:

/** _ptiddata _getptd(void) - get per-thread data structure for the current thread

换句话说,srand的时候,仅仅是把种子设置到当前线程的数据块中。这是线程相关的(就像一个ThreadLocal)。如果之后调用rand()是在另外一个线程中,那么还是默认的随机数种子。这就是这个bug的原因:srand() 和 rand() 发生在不同的线程中。

最后确认一下rand()函数:
int __cdecl rand (        void        )
{
        _ptiddata ptd = _getptd();
        return( ((ptd->_holdrand = ptd->_holdrand * 214013L
            + 2531011L) >> 16) & 0x7fff );
}
果然是从当前线程的数据中获得种子,然后算出一个伪随机数。
最后自己写段程序确认下这个问题:
void run(void *) {
   printf("thread: %d %d %d\n", rand(), rand(), rand());
   srand(123);
   printf("thread: %d %d %d\n", rand(), rand(), rand());
}
int main(int argc, char* argv[]) {
   printf("main: %d %d %d\n", rand(), rand(), rand());
   srand(123);
   printf("main: %d %d %d\n", rand(), rand(), rand());
   _beginthread(run, 0, NULL);
   getchar();
}
运行结果:
main: 6334 18467 41                                                                           
main: 23075 19053 440                                                                         
thread: 6334 18467 41                                                                         
thread: 23075 19053 440 
与预期相符。第一行,第三行分别是主函数与线程函数中输出的随机数。这时主线程与子线程均未调用srand,按默认的输出,结果一样。
第二行,第四行,主线程与子线程均已设置srand(123),则输出新的序列。
任务描述 欢迎来到宝可梦世界!⚡🐉🔥 在这个任务中,你将与计算机控制的宝可梦进行一场激烈的属性克制对战。你将选择攻击属性(火、 水、 草),而计算机也会随机选择一个属性进行对决。程序将根据属性的相互克制关系判断胜负,并输出结果。 属性对应关系: 火🔥 用整数 0 表示 水💧 用整数 1 表示 草🌿 用整数 2 表示 属性克制规则: 火(0) 烧毁 草(2) → 火胜 水(1) 灭 火(0) → 水胜 草(2) 吸收 水(1) → 草胜 相同属性 → 平局 你可以通过计算 玩家选择 - 计算机选择 的差值来判断胜负: 差值为 1 或 -2 → 玩家赢 差值为 -1 或 2 → 计算机赢 差值为 0 → 平局 相关知识 为了完成本关任务,你需要掌握: 随机数生成 rand()函数 rand() 是 C 语言中的标准库函数,返回一个介于 0 和 RAND_MAX(通常是 32767) 之间的伪随机整数。每次调用 rand() 时,它会生成一个新的随机整数。 如何生成随机数 为了确保每次运行程序时生成的随机数不同,我们使用 srand() 结合 time(0) 作为随机数种子: #include <stdlib.h> #include <time.h> srand(time(0)); // 设置随机种子。但在评测时,请将随机数种子设为1 生成指定范围的随机数 可以使用 取模运算 % 将随机数限制在指定范围之间。 int computer = rand() % 3; // 生成 0、1 或 2 编程要求 计算机随机生成 0(火)、1(水)或 2(草)。 在自测运行时,请使用 srand(time(0)); 来观察结果;在评测时,请将随机数种子设为1,即 srand(1); 。 提示玩家输入 0(火)、1(水)、2(草),并等待玩家输入。 程序根据玩家输入与计算机生成的结果判断胜负并输出。 如果玩家输入无效数据(不是 0、1 或 2),程序应提示输入错误。 测试说明 输入输出示例: (注:红框框选部分为用户输入的内容,其余为输出结果)
03-31
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值