C语言fscanf读取带空格姓名的竖线分隔文件出错求助
问题根源与解决办法
为什么会出现乱码和无限循环?
%s格式符的缺陷:%14s会在遇到第一个空格时停止读取,所以姓名只能读到Larry,剩下的Normal留在输入流中,导致后续的|匹配失败。此时fscanf返回的是成功读取的字段数(比如1),既不是预期的4,也不是EOF,所以循环会无限执行。未正确读取的变量内存未被初始化,输出时就会出现乱码。- 循环条件错误:用
!= EOF作为循环终止条件是错误的。当fscanf匹配失败时,它不会返回EOF,而是返回成功读取的字段数量,这会导致循环一直运行。 - 缓冲区风险:部分字段的缓冲区大小刚好卡着长度,没有预留字符串结束符的位置,容易出现溢出问题。
解决方法
方法一:整行读取后分割(推荐,兼容性更强)
先用fgets读取整行内容,再用strtok按|分割字段,能完美处理含空格的姓名:
#include <stdio.h> #include <string.h> int main() { FILE* patientFile = NULL; char line[100]; int patientNum; char patientName[30]; char phoneDescription[5]; char phoneNumber[11]; patientFile = fopen("patientData.txt", "r"); if (patientFile != NULL) { while (fgets(line, sizeof(line), patientFile) != NULL) { char* token = strtok(line, "|"); if (!token) continue; patientNum = atoi(token); token = strtok(NULL, "|"); if (!token) continue; strncpy(patientName, token, sizeof(patientName)-1); patientName[sizeof(patientName)-1] = '\0'; token = strtok(NULL, "|"); if (!token) continue; strncpy(phoneDescription, token, sizeof(phoneDescription)-1); phoneDescription[sizeof(phoneDescription)-1] = '\0'; token = strtok(NULL, "|\n"); if (!token) continue; strncpy(phoneNumber, token, sizeof(phoneNumber)-1); phoneNumber[sizeof(phoneNumber)-1] = '\0'; printf("%d %s %s %s\n", patientNum, patientName, phoneDescription, phoneNumber); } fclose(patientFile); } else { printf("Failed to open patients file\n"); } return 0; }
方法二:修改fscanf格式串
使用%[^|]格式符匹配到|之前的所有字符(包括空格),同时调整循环条件为判断成功读取4个字段:
#include <stdio.h> int main() { FILE* patientFile = NULL; int patientNum; char patientName[30]; char phoneDescription[5]; char phoneNumber[11]; patientFile = fopen("patientData.txt", "r"); if (patientFile != NULL) { // %29[^|] 表示读取最多29个字符(留1位给结束符),直到遇到|为止 while (fscanf(patientFile, "%d|%29[^|]|%4[^|]|%10s\n", &patientNum, patientName, phoneDescription, phoneNumber) == 4) { printf("%d %s %s %s\n", patientNum, patientName, phoneDescription, phoneNumber); } fclose(patientFile); } else { printf("Failed to open patients file\n"); } return 0; }
关键注意点
- 读取含空格的字符串时,
%s不适用,必须用%[^分隔符]或者整行读取后分割。 - 循环条件必须判断
fscanf的返回值等于预期读取的字段数,避免匹配失败时的无限循环。 - 所有字符数组必须预留至少1位的空间给字符串结束符
\0,防止内存溢出和乱码。
内容的提问来源于stack exchange,提问作者user3385214
相关产品推荐
相关产品推荐

