C语言fscanf读取文件时仅能读取单行的问题排查与解决方法
fscanf仅读取一行即终止的问题排查
核心诱因
- 代码本身缺失循环读取结构:当前逻辑仅执行一次
fscanf调用就走到打印流程,随后程序直接退出,从执行流程上就不存在读取20余行内容的可能,哪怕读取功能完全正常,也只会读一次数据就终止。 - fscanf格式串存在副作用:使用的
fscanf(read,"%s\n",Sound.choice)里的\n,实际作用是匹配任意数量的连续空白字符(换行、空格、制表符),直到碰到第一个非空白有效字符才停止匹配,并非“跳过单个换行”。如果读到文件末尾没有后续非空白内容,这个匹配会直接触碰文件结束符,触发读取中断。 - 缺少必要的安全防护:直接用
%s不限制读取长度,很容易因为输入字符串过长导致数组越界,破坏栈内存;直接把读到的字符串作为printf的参数,如果内容里带%格式符,会引发未定义行为。
修正方案
- 调整fscanf格式串:去掉末尾的
\n,给%s加上和结构体数组长匹配的读取长度限制,比如choice数组长度是16,就写成%15s,留1个字节存字符串结束符,避免越界。 - 增加循环读取逻辑:把单次fscanf调用放到while循环中,通过fscanf的返回值判断读取是否成功,只要成功匹配到预期数量的字段就继续处理,直到碰到文件结束。
- 修正打印逻辑:不要直接把读到的字符串作为printf的格式串,改成显式的字符串占位写法
printf("%s\n", Sound.choice)。 - 补充健壮性判断:增加文件打开失败的分支判断,读完数据后调用
fclose()关闭文件流,避免空指针操作和资源泄漏。
修正后的参考代码:
#include <stdio.h> struct soundInput{ char choice[16]; char type[7]; char sound[10]; char sound2[10]; }; int main() { struct soundInput Sound; FILE *read = fopen("input.txt", "r"); if (read == NULL) { perror("打开input.txt失败"); return 1; } // 循环读取,fscanf成功匹配1个字符串时持续运行 while (fscanf(read, "%15s", Sound.choice) == 1) { printf("%s\n", Sound.choice); } fclose(read); return 0; }
注意:如果input.txt是按行存储的、每行包含空格的完整文本,
fscanf %s是按空白分割字段的,并不会按整行读取,这类场景更适合用fgets逐行读入。
内容的提问来源于stack exchange,提问作者dsb
相关产品推荐
相关产品推荐

