我正在使用fscanf()从文件中读取输入(我知道我应该使用fgets(),但不允许这样做),我不知道如何正确使用格式字符串。
输入格式为: M 03f8ab8,1
我需要将每个字母,地址和数字保存到一个变量中。这是到目前为止我得到的:
while(fscanf(file, " %s %s, %d", operation, address, &size) != -1)
按照书面规定,它将字母放入正确的var(operation)中,但在地址末尾添加,number,然后将未定义的内容分配给size变量。
它应该将每个变量放到各自的变量中(并忽略逗号)
如何设置fscanf()才能正确获取此信息?
答案 0 :(得分:5)
这里的问题是"%s"
格式读取以空格分隔的字符串,并且由于03f8ab8,1
中没有空格,因此将它们全部读取为单个字符串。>
您可以使用"%["
格式解决此问题,该格式使您可以进行一些非常简单的模式匹配。例如,您可以使用它来告诉fscanf
阅读所有内容,直到(但不包括)逗号为止。喜欢
fscanf(file, "%s %[^,], %d", operation, address, &size)
例如参见this scanf
(and family) reference了解更多详情。
此外,您不应该将fscanf
与-1
的结果进行比较,而是通过将返回值与3
进行比较来检查它是否解析了正确的序列数:
while (fscanf(file, "%s %[^,], %d", operation, address, &size) == 3) ...
请注意,以上格式不会对其读取的字符串施加任何限制。这可能会导致字符串溢出。如果您的字符串是固定大小的(即它们是数组),请使用格式最大字段宽度来限制fscanf
将读取并放入您的数组中的字符数。
例如(完全不了解您的实际字符串/数组):
while (fscanf(file, "%1s %8[^,], %d", operation, address, &size) == 3) ...
使用上述命令,第一个字符串不能超过一个字符,第二个字符串不能超过八个字符。请注意,这些数字不包括字符串null终止符(您的数组中需要超出上述大小的空间)。
答案 1 :(得分:1)
fscanf(input_fp, "%30[^ ,\n\t]%30[^ ,\n\t]%30[^ ,\n\t]", ...
不会在文本文件中使用','或'\ n'。随后的fscanf()尝试也会失败,并返回值0(不是EOF)会导致无限循环。
fscanf()
解决方案,fgets()/sscanf()
可以更好地处理潜在的IO和解析错误:
main()
{
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') {
变为true:
1)确切地说,每个scanf的3个"%29[^ ,\n\t]"
格式说明符中的每个至少1个字符。
2)buf [n]是字符串的结尾。 n通过“%n”说明符设置。 “%n”中的前一个''导致最后一个"%29[^ ,\n\t]"
之后的任何后续空白都将被消耗。 scanf()看到“%n”,它指示它设置从扫描开始的当前偏移量,以将其分配给&n指向的int。
"VFMT "," VFMT "," VFMT " %n"
由编译器连接到
" %29[^ ,\n\t], %29[^ ,\n\t], %29[^ ,\n\t] %n".
我发现前者比后者更易于维护。
" %29[^ ,\n\t]"
中的第一个空格指示sscanf()扫描(消耗并不保存)0个或多个空格('','\ t','\ n'等)。其余的指示sscanf()消耗并保存除“,”,“ \ n”,“ \ t”以外的任何1到29个字符,然后附加“ \ 0”。