我有一个包含这样数据的文件 -
Name, Age, Occupation
John, 14, Student
George, 14, Student
William, 23, Programmer
现在,我想读取数据,以便将每个值(例如姓名,年龄等)读取为字符串。
这是我的代码片段 -
....
if (!(ferror(input_fp) || ferror(output_fp))) {
while(fscanf(input_fp, "%30[^ ,\n\t]%30[^ ,\n\t]%30[^ ,\n\t]",
name, age_array, occupation) != EOF){
fprintf(stdout, "%-30s%-30s%-30s\n", name, age_array, occupation);
}
fclose(input_fp);
fclose(output_fp);
}
....
然而,这会进入一个无限循环,给出一些随机输出
这就是我理解input conversion specifiers
的方式
%30[^ ,\n\t]
- >读取最多30个字符长的字符串,不要包括空格,逗号,换行符或制表符。
我正在阅读3这样的字符串
我哪里错了?
答案 0 :(得分:7)
OP的
fscanf(input_fp, "%30[^ ,\n\t]%30[^ ,\n\t]%30[^ ,\n\t]", ...
不会消耗文本文件中的','
和'\n'
。后续fscanf()
次尝试也会失败并返回值0(不是EOF
)会导致无限循环。
虽然OP请求fscanf()
解决方案,但fgets()/sscanf()
可以更好地处理潜在的IO和解析错误。
FILE *input_fp;
FILE *output_fp;
char buf[100];
while (fgets(buf, sizeof buf, input_fp) != NULL) {
char name[30]; // Insure this size is 1 more than the width in scanf format.
char age_array[30];
char occupation[30];
#define VFMT " %29[^ ,\n\t]"
int n; // Use to check for trailing junk
if (3 == sscanf(buf, VFMT "," VFMT "," VFMT " %n", name, age_array,
occupation, &n) && buf[n] == '\0') {
// Suspect OP really wants this width to be 1 more
if (fprintf(output_fp, "%-30s%-30s%-30s\n", name, age_array, occupation) < 0)
break;
} else
break; // format error
}
fclose(input_fp);
fclose(output_fp);
不是致电ferror()
,而是检查fgets()
,fprintf()
的返回值。
怀疑OP未声明的字段缓冲区为[30]
并相应调整scanf()
。
[编辑]
有关if (3 == sscanf(buf, VFMT "," ...
if (3 == sscanf(...) && buf[n] == '\0') {
在以下情况下成为真实:
1)确切地说3 "%29[^ ,\n\t]"
格式说明每个scanf至少1 char
2)buf[n]
是字符串的结尾。 n
是通过"%n"
说明符设置的。 ' '
中的前一个" %n"
会导致在最后"%29[^ ,\n\t]"
之后使用任何后续空格。 scanf()
看到"%n"
,指示它设置从扫描开始的当前偏移量,以便分配给int
指向的&n
。
"VFMT "," VFMT "," VFMT " %n"
由编译器连接到
" %29[^ ,\n\t], %29[^ ,\n\t], %29[^ ,\n\t] %n"
。
我发现前者比后者更容易维护。
" %29[^ ,\n\t]"
中的第一个空格指示sscanf()
扫描(消耗而非保存)0个或更多空格(' '
,'\t'
,{{1}等等)。其他人指示'\n'
使用并保存任何 1到29 sscanf()
,但 char
,','
,{{ 1}},然后追加'\n'
。
答案 1 :(得分:2)
您没有跳过值之间的实际逗号和空格。
第一个%30[^ ,\n\t]
说明符匹配后,输入可能包含逗号和空格,格式字符串中的以下内容不匹配。
在输入中预期的格式字符串中添加逗号和空格:
while(fscanf(input_fp, "%30[^ ,\n\t], %30[^ ,\n\t], %30[^ ,\n\t]", name, age_array, occupation) == 3)
^ ^
| |
\ /
add these to make
fscanf() skip them
in the input!
此外,检查fscanf()
的返回值是次优的:在依赖要转换的值之前,您应该检查返回值是否等于转换次数。
另外,你使用反斜杠续行字符是完全没有意义的,应该删除。