C语言中如何以EOF为条件终止循环?类奥赛罗游戏文件读取循环异常求助
C语言中如何以EOF为条件终止循环?类奥赛罗游戏文件读取循环异常求助
兄弟,你的问题核心出在没正确检查文件读取是否到达EOF,还有几个细节处理失误,导致循环停不下来还重复输出最后一行,我给你拆解并解决:
先说说你当前代码的几个关键问题:
- 循环条件完全错误:
EOF != 1这个判断毫无意义,EOF是C标准定义的宏(通常值为-1),这个条件永远为真,循环自然停不下来。而且你根本没检查每次读取是否成功,到了EOF后jugada里还保留着最后一次读取的内容,所以printf会一直重复输出。 toupper用法错误:toupper(jugada[0])只是返回转换后的大写字符,不会修改原数组里的内容,必须把返回值赋值回去才有用。- 读取函数没做EOF判断:你的
tomaJugada函数不管fgets是否读取成功,都直接修改jugada,完全没利用fgets的返回值来识别EOF。 - 硬设终止符不安全:直接给
jugada[2] = '\0',如果读取的行长度不足2(比如示例里的单个字符"B"),会修改数组的未知内存,可能引发奇怪问题。
给你修改后的解决方案:
第一步:修正tomaJugada函数,让它能识别EOF
把函数改成返回值类型,用fgets的返回值判断是否到达EOF:
#include <string.h> // 要包含这个头文件用strcspn // 返回1表示成功读取一行,返回0表示到达EOF或读取错误 int tomaJugada(FILE** fp, char jugada[]) { // fgets返回NULL时,说明到了EOF或者读取出错 if (fgets(jugada, 5, *fp) == NULL) { return 0; } // 用strcspn去掉换行符,比硬设下标更安全,适配不同长度的行 jugada[strcspn(jugada, "\n")] = '\0'; return 1; }
第二步:修正主循环逻辑,基于读取结果控制循环
同时还要处理不同格式的行(比如单个字符的颜色选择、两位的坐标),避免转换出错:
#include <ctype.h> // 包含toupper、isdigit的头文件 // 假设error是你定义的int指针,先初始化错误标识为0 *error = 0; while (!*error) { // 先判断是否成功读取一行,没成功就退出循环(到EOF了) if (!tomaJugada(&fp, jugada)) { break; } // 处理不同类型的行: size_t len = strlen(jugada); if (len == 1) { // 这是颜色选择行(比如示例里的"B") char color = toupper(jugada[0]); printf("读取到颜色选择:%c\n", color); continue; } else if (len >= 2) { // 处理坐标行(比如"D6") jugada[0] = toupper(jugada[0]); // 这里要赋值回去,才算真正转大写 int columna = convierte_a_int(jugada[0]) - 1; // 先判断第二个字符是不是数字,避免非法输入 if (isdigit(jugada[1])) { int fila = (jugada[1] - '0') - 1; printf("columna %i, fila %i \n", columna, fila); } else { *error = 1; printf("非法的坐标格式!\n"); } } else { // 空行直接跳过 continue; } }
额外说明:
- 关于你提到的
getc用法:确实如果直接用getc检查EOF,会消耗一个字符,需要用ungetc(ch, fp)把字符放回输入流,但这种方式不如fgets直接,因为你需要读取整行内容,fgets更适配你的场景。 - 一定要注意输入的合法性判断,比如坐标里的数字是否在1-8之间,字母是否在A-H之间,避免数组越界或者逻辑错误。
备注:内容来源于stack exchange,提问作者dumping the core
相关产品推荐
相关产品推荐

