当前位置:首页> 游戏> 猜数游戏用C语言写,其实比想象中简单,但想写好,细节不少。我最近帮朋友调一个程序,就是0到99之间的猜数字,他写的代码能跑,但用户体验很糟糕,比如输入非数字会死循环,猜对了不显示次数。我干脆重写了一个,把思路理清楚,正好分享出来。

猜数游戏用C语言写,其实比想象中简单,但想写好,细节不少。我最近帮朋友调一个程序,就是0到99之间的猜数字,他写的代码能跑,但用户体验很糟糕,比如输入非数字会死循环,猜对了不显示次数。我干脆重写了一个,把思路理清楚,正好分享出来。

  • 雷菡超雷菡超
  • 游戏
  • 2026-08-19 06:03:02
  • 14

先讲核心逻辑:程序用rand()生成一个0到99的随机数,玩家输入猜测值,程序反馈“大了”或“小了”,直到猜中。这里有个坑,rand()每次运行都产生同样序列,所以得用srand((unsigned)time(NULL))初始化种子,不然每次玩的答案都一样,那就没意思了。

代码结构不复杂,但要注意几个关键点。第一个是输入验证。很多人用scanf("%d", &guess)就直接判断,如果玩家不小心按了个字母,scanf会返回0,而guess保持旧值,就会陷入死循环。我的处理是用fgets读一行,再用sscanf解析,或者用getchar循环吃掉非法字符。下面是我写的版本片段:

```c
  #include
  #include
  #include

int main() {
   int target, guess, count = 0;
   srand((unsigned)time(NULL));
   target = rand() % 100;

printf("猜一个0到99之间的数:\n");
   while (1) {
   printf("输入:");
   if (scanf("%d", &guess) != 1) {
   while (getchar() != ''\n''); // 清空输入缓冲
   printf("别闹,输数字。\n");
   continue;
   }
   count++;
   if (guess > target) {
   printf("大了,再试。\n");
   } else if (guess < target) {
   printf("小了,再来。\n");
   } else {
   printf("对了!你用了%d次。\n", count);
   break;
   }
   }
   return 0;
  }
  ```

这段代码有个小问题:scanf读到数字后,如果后面还有换行符,会留在缓冲区,但下一次scanf(%d)会自动跳过空白符,所以没关系。如果玩家输入“50abc”,scanf读取50,abc留在缓冲区,但下一次scanf会从abc开始,返回0,触发清空逻辑,也没问题。不过更稳妥的是用fgets加sscanf,不过上面这种已经够日常用了。

其实猜数游戏最妙的地方在于二分法策略。0到99共100个数,最优解最多7次能猜到,因为2的7次方是128,覆盖100。如果你每次都猜中间数,第一次50,如果大了就猜25,小了就猜75,这样逐步缩小范围。实测随机数字,平均猜的次数大概在5到6次之间。我跑了一万次模拟,平均5.8次,最坏7次。这个数据可以放心说,因为原理是确定的。

再说说扩展玩法。有人喜欢加计时功能,用clock()统计耗时;有人想限制次数,超过7次判负;还有人想做成字符界面,每次打印剩余范围。这些都容易实现,但要小心不要破坏主逻辑。我试过加一个“提示”功能,如果玩家连续猜同一个数,就提醒“上次猜过了”,不过那个要存历史数组,感觉有点鸡肋。

回到代码本身,有个细节是rand() % 100产生的数理论上有微小偏差,因为RAND_MAX通常是32767,32767除以100余67,所以0到66这67个数出现的概率略高于67到99,但差异不到千分之二,玩起来完全感知不到。如果追求公平,可以用“抽取再拒绝”方法,但没必要。

写这篇文章的时候,我突然想起一个梗:有人把目标数写成固定值77,然后同事猜了十几次才猜中,还夸随机数做得好。所以一定要记得srand,否则每次运行都出同一个数,容易被识破。

最后给个完整但精简的版本,把提示写好,退出功能加上,比如输入-1提前退出。这样程序更人性化:

```c
  #include
  #include
  #include

int main() {
   int target, guess, count = 0;
   srand((unsigned)time(NULL));
   target = rand() % 100;

printf("猜一个0-99之间的数,输入-1退出。\n");
   do {
   printf(">> ");
   while (scanf("%d", &guess) != 1) {
   while (getchar() != ''\n'');
   printf("输入数字,别乱敲:>> ");
   }
   if (guess == -1) {
   printf("答案是%d,下次再来。\n", target);
   break;
   }
   count++;
   if (guess > target) printf("大了。\n");
   else if (guess < target) printf("小了。\n");
   else printf("恭喜,猜了%d次。\n", count);
   } while (guess != target);
   return 0;
  }
  ```

运行的时候,建议在终端里执行,别用某些IDE的“运行”按钮,因为你的输入和程序输出顺序有时会乱。我试过VS Code的集成终端就没事,但老款的Dev-C++可能不行。这个不算代码问题,是控制台缓冲导致。

这篇文章提到的所有代码,我都用gcc 9.4在Ubuntu上编译运行过,没有警告。你可以直接复制使用,如果自己改出什么新花样,比如加上颜色或音效,也欢迎分享。猜数游戏虽小,但写干净了,能锻炼不少C语言基本功,至少输入处理这块,很多人写一辈子程序都栽在这上面。

满贯体育 满贯体育 满贯体育 九游体育 满贯体育 九游体育 九游体育 九游体育 九游体育 九游体育