C语言猜单词程序字符匹配标记输出异常问题排查
C语言猜单词程序逻辑错误排查
规则说明
程序实现5字母猜单词玩法,对比秘密单词与用户输入的猜测单词时,按如下规则标记字符:
- 位置和字符完全匹配:标记为
/ - 字符存在于秘密单词中但位置错误:标记为
+ - 字符未在秘密单词中出现:标记为
*
问题现象
现有代码仅部分场景运行正常,典型异常复现路径:
- 输入秘密单词为
amore - 输入猜测单词为
astio - 程序实际输出
/****,预期正确输出应为/***+
问题原代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #define SIZE 40 int main(int argc, char *argv[]) { int i,j,flag=0,k=0, N=5; char par[5],cod[5], sol[5], sol2[5]; printf("insert the segret word: "); scanf("%s[^n]",par); getchar(); /*for(i=0; i<5; i++){ if(par[i]==cod[i]) k++; }*/ while(flag==0){ k=0; printf("INSERT WORD: "); scanf("%s[^n]",cod); getchar(); for(i=0; i<5; i++){ if(par[i]==cod[i]) k++; } //printf("%d",k); if(k==4){ printf("WINNER ...."); flag=1; //printf("%d",flag); } else{ for(i=0; i<5; i++){ for(j=0; j<5; j++){ /*if(i=0 && j==0 ) printf("vollllll");*/ //sol[0]='/';*/ if(par[i]==cod[j] && i==j){ sol[i]='/'; //sol2[i]= '/'; if(sol[i]=='*' || sol[i]=='+'){ sol[i]=' '; sol[i]='/'; } } else if(par[i]==cod[j] && i!=j){ sol[j]== '+'; //sol2[j]== '+'; if(sol[j]=='*'){ sol[j]=' '; sol[j]='+'; } } else if(i==j && par[i]!=cod[j]){ //sol[j]==' ')' sol[i]= '*'; } } } for(i=0;i<5;i++) printf("%c",sol[i]); printf("\n"); } } return 0; }
核心错误点
- 语法错误:比较符误用为赋值符
错位匹配分支中写的sol[j]== '+';是相等判断表达式,不会对数组元素做赋值操作,所有错位匹配的+标记根本不会被写入结果数组,这是复现场景输出异常的直接原因。 - 数组长度不足引发内存越界
存储单词的par、cod、sol数组长度均定义为5,C语言字符串需要1字节存储末尾结束符\0,存储5字母单词至少需要6字节长度,否则会出现随机内存读写,引发不可预期的异常。 - 胜利判断逻辑错误
现有代码判定胜利的条件是k==4,即匹配4个字符就提示胜利,但5字母单词需要全部位置匹配正确才算胜利,正确条件应为k==5。 - 标记逻辑顺序混乱,存在覆盖问题
双层循环遍历过程中,后续逻辑会覆盖之前写入的正确标记:比如已经标记为/的正确匹配,可能被后续逻辑覆盖为*;同时没有做字符匹配计数,同一个秘密字符会被重复匹配给多个猜测字符,遇到含重复字母的单词时标记结果完全错误。 - 输入写法存在溢出风险
scanf("%s[^n]",par)是错误格式,且没有限制输入长度,用户输入超过数组长度时会直接触发缓冲区溢出。
修复后代码
修复后采用两遍遍历逻辑,先标记所有位置正确的匹配,再标记错位匹配,同时增加已匹配字符标记避免重复计数,修复所有语法和逻辑问题:
#include <stdio.h> #include <stdlib.h> #include <string.h> #define WORD_LEN 5 int main() { int i, j, flag = 0, k = 0; // 数组长度+1,预留字符串结束符位置 char par[WORD_LEN + 1], cod[WORD_LEN + 1], sol[WORD_LEN + 1]; // 标记秘密单词中已被匹配的字符位置,避免重复匹配 int matched[WORD_LEN] = {0}; printf("insert the secret word: "); scanf("%5s", par); // 限制最大读入长度,防止缓冲区溢出 getchar(); while (flag == 0) { k = 0; // 每轮猜测重置标记数组和结果数组 memset(matched, 0, sizeof(matched)); memset(sol, '*', WORD_LEN); // 先默认所有字符为未匹配状态 sol[WORD_LEN] = '\0'; printf("INSERT WORD: "); scanf("%5s", cod); getchar(); // 第一遍遍历:标记所有位置完全匹配的字符 for (i = 0; i < WORD_LEN; i++) { if (par[i] == cod[i]) { k++; sol[i] = '/'; matched[i] = 1; } } // 全部字符匹配正确则判定胜利 if (k == WORD_LEN) { printf("WINNER ...."); flag = 1; } else { // 第二遍遍历:标记错位匹配的字符 for (i = 0; i < WORD_LEN; i++) { if (sol[i] == '/') continue; // 已标记为位置正确的直接跳过 for (j = 0; j < WORD_LEN; j++) { // 找到未被使用的秘密字符与当前猜测字符匹配 if (!matched[j] && cod[i] == par[j]) { sol[i] = '+'; matched[j] = 1; break; } } } printf("%s\n", sol); } } return 0; }
内容的提问来源于stack exchange,提问作者Ridovic Paco Rabanne
相关产品推荐
相关产品推荐

