C语言scanf输入异常、循环重复输出问题排查求助
排查C代码中文件操作与输入循环的两个问题
我来帮你拆解这两个问题的根源,以及对应的修复方案:
问题1:TOS输入环节重复输出“TOS:”提示
原因
在TOS的验证循环中,当你输入的内容不匹配文件中的任何行时,while(fgets(line, BUFFER_SIZE, fptr))会一直读取到文件末尾,此时文件指针停留在文件结尾。而你只在整个TOS循环结束后调用了rewind(fptr),循环内部每次验证失败时没有重置指针,导致下一次循环时fgets直接返回NULL,根本不会进入匹配检查的循环,stat始终为0,因此会一直重复输出“TOS:”提示。
修复
在每次执行while(fgets...)匹配检查前,先调用rewind(fptr)将文件指针重置到文件开头,确保每次验证都从文件起始位置读取内容,同时找到匹配后直接跳出循环提升效率:
stat = 0; while (stat == 0) { printf("TOS: "); scanf("%s", tos); rewind(fptr); // 每次检查前重置文件指针 while (fgets(line, BUFFER_SIZE, fptr) != NULL) { if (strstr(line, tos)) { stat = 1; break; // 找到匹配后直接结束读取 } } }
问题2:部分输入步骤被跳过,直接进入Total Fee环节
原因
这个问题主要由三个错误叠加导致:
- 数组参数传递错误:你在
scanf中给数组加了&,比如scanf("%s", &v_id);。数组名v_id本身就是指向数组首元素的指针,加&会导致类型不匹配,这种未定义行为可能破坏内存中的其他变量(比如stat的值),导致循环提前结束,跳过输入步骤。 - 文件指针重置不及时:和TOS的问题一样,Customer Status、Needed Days的验证循环中,都没有在每次检查前重置文件指针,导致文件指针停留在末尾,无法读取内容,可能意外让
stat的逻辑出错。 - getchar()的滥用:在TOS和Customer Status输入后调用
getchar(),如果输入缓冲区中没有多余字符,getchar()会等待用户输入,反而打乱流程;scanf("%s")本身会自动跳过开头的空白字符(包括换行),不需要额外调用getchar()。
修复
- 所有
scanf中传递数组参数时,去掉&,比如scanf("%s", v_id);、scanf("%s", tos);等。 - 每个输入验证循环中,都在
fgets检查前调用rewind(fptr)重置指针。 - 去掉不必要的
getchar()调用。
完整修复后的代码示例
#include <stdio.h> #include <string.h> #include <stdlib.h> #define BUFFER_SIZE 1024 // 定义合理的缓冲区大小 int main() { int stat; char v_id[100], c_id[100], line[BUFFER_SIZE], tos[100], cust_stat[100], n_daysasd[100], tot_fee[100]; printf("Enter Visitor ID: "); scanf("%s", v_id); printf("Enter Customer ID: "); scanf("%s", c_id); FILE* fptr2; FILE* fptr; FILE* ftemp; // 添加文件打开失败判断,增强健壮性 if ((fptr = fopen(v_id, "r")) == NULL) { perror("Failed to open visitor file"); return 1; } if ((fptr2 = fopen("servicestest.txt", "r")) == NULL) { perror("Failed to open servicestest.txt"); fclose(fptr); return 1; } if ((ftemp = fopen("replacetemp.txt", "w")) == NULL) { perror("Failed to create temp file"); fclose(fptr); fclose(fptr2); return 1; } // 打印文件内容 while (fgets(line, BUFFER_SIZE, fptr)) { printf("%s\n", line); } printf("\nEnter the information accordingly\n"); rewind(fptr); // TOS输入验证 stat = 0; while (stat == 0) { printf("TOS: "); scanf("%s", tos); rewind(fptr); while (fgets(line, BUFFER_SIZE, fptr) != NULL) { if (strstr(line, tos)) { stat = 1; break; } } } // Customer Status输入验证 stat = 0; while (stat == 0) { printf("Customer Status: "); scanf("%s", cust_stat); rewind(fptr); while (fgets(line, BUFFER_SIZE, fptr) != NULL) { if (strstr(line, cust_stat)) { stat = 1; break; } } } // Needed Days输入验证 stat = 0; while (stat == 0) { printf("Needed days: "); scanf("%s", n_daysasd); rewind(fptr); while (fgets(line, BUFFER_SIZE, fptr) != NULL) { if (strstr(line, n_daysasd)) { stat = 1; break; } } } // Total Fee输入验证 stat = 0; while (stat == 0) { printf("Total Fee: "); scanf("%s", tot_fee); rewind(fptr); while (fgets(line, BUFFER_SIZE, fptr) != NULL) { if (strstr(line, tot_fee)) { stat = 1; break; } } } // 更新servicestest.txt内容 rewind(fptr2); while (fgets(line, BUFFER_SIZE, fptr2)) { if (strstr(line, v_id)) { fprintf(ftemp, "Visit ID: %s, Customer ID : %s, TOS : %s, Customer Status : %s, Needed Days : %s, Total Fee : %s, Payment : Not Made\n", v_id, c_id, tos, cust_stat, n_daysasd, tot_fee); } else { fputs(line, ftemp); } } fclose(fptr); fclose(fptr2); fclose(ftemp); remove("servicestest.txt"); rename("replacetemp.txt", "servicestest.txt"); return 0; }
额外建议
- 记得添加必要的头文件,否则
strstr、perror等函数会报错。 - 在
fprintf的末尾添加\n,避免写入的内容和下一行连在一起,保持文件格式整洁。 - 添加文件打开失败的判断,能快速定位文件不存在、权限不足等问题。
内容的提问来源于stack exchange,提问作者Lorale
相关产品推荐
相关产品推荐

