C语言随机数生成机制与猜数字游戏实现

1 伪随机数生成的核心机制

C语言标准库通过rand函数提供随机数生成能力,但其本质属于伪随机数(Pseudo-Random Number),而非物理意义上的真随机数。

1.1 rand 函数的工作特性

rand函数原型如下:

c 复制代码
int rand(void);

该函数返回一个介于0到RAND_MAX之间的整数。在大多数编译器中,RAND_MAX的值为 32767。

关键特性:

  • rand并非真正随机,而是通过确定性算法计算得出;
  • 其输出依赖于一个称为 种子 (seed) 的初始值;
  • 默认情况下,种子固定为1,因此每次程序运行生成的随机数序列完全一致。

若不更改种子,多次运行程序将得到相同的"随机"结果,这在游戏或安全场景中是不可接受的。

2 种子初始化与 srand 函数

为使随机数序列发生变化,必须在调用rand之前初始化种子。

srand函数用于设置随机数生成器的种子,原型为:

c 复制代码
void srand(unsigned int seed);

只要种子发生变化,rand生成的序列就会随之改变。

然而,这引出了一个递归问题:

若想生成随机数,需先有一个随机的种子;但获取随机种子本身又需要随机数。

为了解决该矛盾,通常采用时间作为种子来源。

3 基于时间戳的动态种子

3.1 time函数与时间戳

C语言提供time函数以获取当前时间,其原型为:

c 复制代码
time_t time(time_t *timer);
  • 返回值表示从 1970年1月1日 00:00:00 UTC 到当前时刻的秒数,称为时间戳;
  • 参数通常为NULL,仅返回时间差值;
  • 返回类型为time_t,本质是整数类型。

3.2 完整初始化流程

结合time与srand,即可实现动态种子初始化:

c 复制代码
#include <stdlib.h>
#include <time.h>

srand((unsigned int)time(NULL));

注意:srand只需在程序生命周期中调用一次,频繁调用(尤其在短时间内)会导致种子重复,进而产生相同随机数。

4 猜数字游戏的综合实现

猜数字游戏是分支与循环结构的典型综合应用,其核心逻辑包括:随机数生成、用户输入、条件判断与循环控制。

c 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<time.h>

void menu() {
	printf("===================================\n");
	printf("=======Number Guessing Game========\n");
	printf("===== 1 PLAY === 0 GAME OVER ======\n");
	printf("===================================\n");
}

void play() {
	int sysget = rand() % 100 + 1;
	printf("%d\n", sysget);
	printf("******************************************\n");
	printf("Please enter an integer between 1 and 100:\n");
	int get = 0;
	int count = 0;
	while (sysget != get) {
		count++;
		scanf("%d", &get);
		if (get > sysget) {
			printf("[COUNT:%d] WARNING: too high.\n", count);
		}
		else if (get < sysget) {
			printf("[COUNT:%d] WARNING: too low.\n", count);
		}
		else {
			printf("Congratulations to you.\n");
			printf("\n");
			break;
		}
		if (count == 5) {
			printf("Maximum attempts reached, GAME FAILED.\n");
			printf("\n");
			break;
		}
	}
}

int main() {
	int input = 0;
	srand((unsigned int)time(NULL));
	do {
		menu();
		printf("Please Select:\n");
		scanf("%d", &input);
		switch (input) {
		case 1:
			play();
			break;
		case 0:
			printf("Exit Game\n");
			break;
		default:
			printf("Input error.\n");
			break;
		}
	} while (input);
	return 0;
}
相关推荐
死磕音视频10 小时前
让小模型做选择题:限定候选项并读取 logits 概率的入门实践(附 Python 代码)
开发语言·python·大模型·文本分类·transformers
Navigator_Z10 小时前
LeetCode //C - 1291. Sequential Digits
c语言·算法·leetcode
顽疲12 小时前
Java vue 养老系统源码详解:月账单 care_month_bill 与 Quartz 扣费 Job 实践
java·开发语言·vue.js·vue养老·springboot养老·java养老
Wang's Blog12 小时前
Java 项目实战: 交友项目 - 安装开发工具与环境准备
java·开发语言·交友
水饺编程13 小时前
第2章:Linux 基础,clear 命令
linux·c语言·汇编
程序喵大人14 小时前
【C++入门】编译链接模型 - 07 链接器怎样把符号对上号
开发语言·c++·编译器·编译链接·链接器
无敌贵点大王14 小时前
嵌入式软件面试经(自用)
c语言·stm32·单片机·学习·mongodb·面试·职场和发展
微三云 - 廖会灵 (私域系统开发)14 小时前
供应链系统实战:多渠道订单聚合与分布式库存一致性方案总结
开发语言·分布式·php
学逆向的15 小时前
C 数据溢出与精度丢失
c语言·开发语言·网络安全
霸道流氓气质15 小时前
AgentFlow 入门与实战:Task-Based 并发、EWMA 动态调度与四道门禁的 Java 生产级编排
java·开发语言