C语言Hangman游戏异常:输入第3个字符后程序崩溃
Hangman游戏C代码终止问题排查与修复建议
问题描述
这是一个基础的Hangman(猜词)游戏C语言代码,运行时输入第3个字符后程序会突然终止。已在2个本地IDE及在线编译器测试,均出现该逻辑错误,请求排查问题并给出解决建议。
原代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> int chances = 5; //可修改剩余次数 char sentence[20]; //单词缓冲区,修改长度时需同步调整indicator的长度 char indicator[20]; //显示猜词进度的占位符 char character; //存储玩家输入的字符 int woncheck = 0; void status(); //声明函数 void check(); //声明函数 void main() { printf("Wellcome to my hangman game"); printf("Player 1 please enter your sentence [Max 20 character] ==> "); gets(sentence); //读取玩家1输入的单词 while (strlen(sentence)>=20) //检查输入长度是否超标 { printf("Please enter max 20 character ==> "); gets(sentence); } for (int i = 0; i < strlen(sentence); i++) { //初始化占位符,非空格字符用_代替 if (sentence[i] != ' ') { indicator[i] = '_'; } else { indicator[i] = ' '; } } printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); //清屏 status(); //显示初始猜词进度 for (int j = 0; j < chances ; j++) //循环次数等于剩余机会数 { woncheck = 1; //初始化胜利标记 for (int k = 0; k < strlen(sentence); k++) { if (indicator[k] == '_') { //如果还有未猜中的字符,标记未胜利 woncheck = 0; break; } } if (woncheck == 1) { printf("Player 1 won the game\n"); break; } printf("Player 2 please enter 1 character ==> "); //提示玩家2输入字符 scanf(" %c",&character); printf("\n"); chances--; //剩余机会减1 check(); //检查输入字符是否匹配 status(); //更新显示当前进度 if (chances == 0) { printf("Player 1 lost the game\n"); break; } } } void status() { for (int i = 0; i < strlen(sentence); i++) //遍历单词长度显示占位符 { printf("%c ",indicator[i]); //打印占位符 } printf("You have %d chances left. \n \n",chances); } void check() { for (int i = 0; i < strlen(sentence); i++) { if (toupper(sentence[i]) == toupper(character)) //不区分大小写检查字符匹配 { indicator[i] = character; } } }
问题排查
- 循环逻辑冲突导致提前终止
主循环使用for (int j = 0; j < chances ; j++)作为条件,但循环体内每次执行chances--,使得循环的终止条件动态缩小:
- 初始
chances=5,第一次循环后chances=4 - 第二次循环后
chances=3 - 第三次循环后
chances=2 - 此时
j递增到3,3 < 2不成立,循环直接终止,表现为输入3次后程序停止,并非崩溃。
indicator数组未添加字符串终止符
初始化indicator时仅设置了与sentence长度对应的字符,但未在末尾添加'\0'。虽然当前status函数用strlen(sentence)控制循环长度,但后续若有依赖字符串终止符的操作会引发未定义行为。gets函数不安全且已废弃gets不检查输入长度,若用户输入超过sentence的缓冲区大小(20字节),会导致缓冲区溢出,引发程序崩溃或其他未定义行为。胜负判断逻辑颠倒
原代码中,当玩家2猜对所有字符时,输出"Player 1 won the game",与实际游戏逻辑(玩家2猜中单词获胜)不符。
修复建议
1. 修正循环逻辑
使用独立变量记录剩余机会,避免修改循环条件中的变量,确保循环执行次数符合预期:
int remaining_chances = chances; while (remaining_chances > 0) { // 原有循环体逻辑 }
2. 给indicator添加终止符
在初始化indicator的循环结束后,添加终止符:
int len = strlen(sentence); for (int i = 0; i < len; i++) { // 初始化逻辑 } indicator[len] = '\0';
3. 替换gets为fgets
fgets可指定最大读取长度,避免缓冲区溢出,同时移除读取到的换行符:
printf("Player 1 please enter your sentence [Max 20 characters] ==> "); fgets(sentence, sizeof(sentence), stdin); sentence[strcspn(sentence, "\n")] = '\0'; // 移除换行符
4. 修正胜负判断逻辑
当玩家2猜中所有字符时,输出玩家2获胜;当机会耗尽未猜中时,输出玩家1获胜:
if (woncheck == 1) { printf("Player 2 won the game!\n"); break; } // ... if (remaining_chances == 0) { printf("Player 1 won the game! The word was: %s\n", sentence); break; }
5. 优化机会扣除逻辑
只有当玩家猜错字符时才扣除机会,而非每次输入都扣除:
int found = check(); // 修改check函数返回是否找到匹配字符 if (!found) { remaining_chances--; }
修复后的完整代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> int chances = 5; char sentence[20]; char indicator[20]; char character; void status(int remaining); int check(); int main() { printf("Welcome to my hangman game!\n"); printf("Player 1 please enter your sentence [Max 20 characters] ==> "); fgets(sentence, sizeof(sentence), stdin); sentence[strcspn(sentence, "\n")] = '\0'; while (strlen(sentence) >= 20) { printf("Please enter max 20 characters ==> "); fgets(sentence, sizeof(sentence), stdin); sentence[strcspn(sentence, "\n")] = '\0'; } int len = strlen(sentence); for (int i = 0; i < len; i++) { if (sentence[i] != ' ') { indicator[i] = '_'; } else { indicator[i] = ' '; } } indicator[len] = '\0'; printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); int remaining_chances = chances; status(remaining_chances); while (remaining_chances > 0) { int woncheck = 1; for (int k = 0; k < len; k++) { if (indicator[k] == '_') { woncheck = 0; break; } } if (woncheck == 1) { printf("Player 2 won the game!\n"); break; } printf("Player 2 please enter 1 character ==> "); scanf(" %c", &character); printf("\n"); int found = check(); if (!found) { remaining_chances--; } status(remaining_chances); if (remaining_chances == 0) { printf("Player 1 won the game! The word was: %s\n", sentence); break; } } return 0; } void status(int remaining) { int len = strlen(sentence); for (int i = 0; i < len; i++) { printf("%c ", indicator[i]); } printf("\nYou have %d chances left.\n\n", remaining); } int check() { int found = 0; int len = strlen(sentence); for (int i = 0; i < len; i++) { if (toupper(sentence[i]) == toupper(character)) { indicator[i] = character; found = 1; } } return found; }
内容的提问来源于stack exchange,提问作者Berat Zengin
相关产品推荐
相关产品推荐

