Hangman游戏失败时无法打印目标词:首字符被改为'\000'问题排查
解决你的Hangman游戏失败时无法打印目标词的问题
嘿,我帮你找到了问题的核心——这是一个典型的栈内存越界写入导致的内存污染,正是它把目标词的首字符改成了'\0',让你没法正常打印出来。咱们一步步拆解问题,然后给出修复方案:
1. 越界写入的罪魁祸首
你定义了char letters[MAX_GUESS+1];,MAX_GUESS是6,所以这个数组总共能存7个字符(下标0到6)。但在循环里你写了:
letters[guesses] = temp_char; letters[guesses+1] = '\0';
当guesses走到6(也就是第6次失败)的时候,guesses+1等于7,这时候你在给letters[7]赋值——这已经超出了数组的合法边界!
C语言的栈变量是连续排布的,letters数组越界写入的这个字节,刚好覆盖了相邻的word数组的第一个字符,把它改成了字符串结束符'\0'——这就是为什么失败时目标词打印不出来的原因。
2. 还有几个需要补的小坑
除了越界问题,代码里还有几个影响逻辑的小问题:
- 未初始化的
input数组:char input[MAX_STRING];没有初始化,一开始里面全是随机垃圾值,导致你第一次循环里的if (word[j] == input[j])判断完全不可靠,初始的下划线显示也不对。 - 重复猜字母会误判失败:用户如果重复输入同一个字母,当前代码会重复计入失败次数,这显然不符合游戏逻辑。
- 循环条件的边界错误:
guesses <= MAX_GUESS会让用户多猜一次,因为guesses从0开始计数,到6的时候已经是第7次尝试,超过了设定的6次失败上限。
3. 修复后的完整代码
这里是把所有问题都修好的版本,逻辑更严谨,也不会再出现内存污染的问题:
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <string.h> #define VOCABULARY_SIZE 8 #define MAX_STRING 32 #define MAX_GUESS 6 int random_number(int a, int b) { return a + rand() % (b - a + 1); } int main() { // 随机选择目标词 srand((unsigned)time(NULL)); const char VOCABULARY[VOCABULARY_SIZE][MAX_STRING] = {"vehicle", "building", "shirt", "pencil", "batman", "dromedary", "peach", "hangman"}; char word[MAX_STRING]; int i = random_number(0, VOCABULARY_SIZE - 1); strcpy(word, VOCABULARY[i]); int guesses = 0, length = strlen(word); char letters[MAX_GUESS + 1] = {0}; // 初始化字母数组为全0,确保字符串合法 char input[MAX_STRING]; // 初始化input为全下划线,和目标词长度匹配,末尾加结束符 memset(input, '_', length); input[length] = '\0'; char temp_char; char temp_input[MAX_STRING]; do { printf("\nYour entered letters are: %s\n", letters); printf("Your letters found are: %s\n", input); // 直接打印input,不用循环判断,更简洁 printf("%d-letter word. %d out of %d failures. Enter a letter: ", length, guesses, MAX_GUESS); scanf(" %c", &temp_char); // 先检查这个字母有没有猜过,避免重复计数 if (strchr(letters, temp_char) == NULL) { int found_match = 0; // 遍历目标词,匹配到字母就更新input for (int j = 0; j < length; j++) { if (word[j] == temp_char) { input[j] = word[j]; found_match = 1; } } // 只有没匹配到的时候,才把字母加入已猜列表,增加失败次数 if (!found_match) { int current_len = strlen(letters); letters[current_len] = temp_char; letters[current_len + 1] = '\0'; guesses++; } } else { printf("You already guessed '%c'! Try another one.\n", temp_char); } printf("\nWhat is the word to guess? "); scanf(" %s", temp_input); } while ((strcmp(input, word) != 0 && strcmp(temp_input, word) != 0) && guesses < MAX_GUESS); // 改成<,确保不超过最大失败次数 // 游戏结束判定 if (strcmp(input, word) == 0 || strcmp(temp_input, word) == 0) { printf("\nCongratulations, the word was %s!\n", word); } else { printf("\nBetter luck next time... The word was %s\n", word); } return 0; }
修复要点总结
- 彻底解决越界问题:现在用
strlen(letters)获取已猜字母的长度,再添加新字母,完全避免了越界写入的风险,同时初始化letters为全0,确保字符串始终有效。 - 初始化
input数组:用memset把input初始化为下划线,初始显示正确,后续的strcmp判断也能正常工作。 - 优化猜字母逻辑:增加了重复猜字母的检测,避免用户重复输入同一个字母却被误判为失败。
- 修正循环边界:把
guesses <= MAX_GUESS改成guesses < MAX_GUESS,确保用户最多只能失败6次,符合游戏设定。
这样修改后,不管玩家获胜还是失败,目标词都能正常打印,游戏逻辑也更流畅啦!
内容的提问来源于stack exchange,提问作者Ivan.2j
相关产品推荐
相关产品推荐

