排队
while(fscanf(out, "%lf %s %s", &value, name, surname) != EOF)
比较函数fscanf和EOF的返回值不好。例如,如果函数只能匹配一个参数,那么它将返回1,但您的程序仍会表现得好像所有3 参数都已匹配,并且您的程序将尝试处理不存在的数据.因此,您应该改写以下内容:
while( fscanf(out, "%lf %s %s", &value, name, surname) == 3 )
但是,这可能不是您遇到的直接问题的原因。该问题可能是由于%s 转换格式说明符需要一个指针来写入。但是,您传递的是单个 char 的值(而不是指针)。
假设您启用了警告,您的编译器应该已经警告过您。有关详细信息,请参阅此问题:Why should I always enable compiler warnings?
为了解决这个问题,你应该换行
char name;
char surname;
到:
char name[50];
char surname[50];
此外,您可能应该限制写入这些字符串的字符数,以防止出现buffer overflow,如下所示:
while( fscanf(out, "%lf %49s %49s", &value, name, surname) == 3 )
对于基于行的输入,我通常建议您使用函数fgets 一次读取一行。然后,您可以在每一行上使用函数 sscanf 来解析它。
如果您像现在一样使用 fscanf,并且如果它与一行中的 3 个字段不完全匹配,那么解析器将与行不同步,并且无法自行重新同步在新行的开头,这可能意味着您的程序将在文件的其余部分出现异常,而不是仅在一行中出现异常。
这是一个使用fgets 和sscanf 代替的程序:
#include <stdio.h>
double get_sum( FILE *fp )
{
char line[200];
double sum = 0;
while ( fgets( line, sizeof line, fp ) != NULL )
{
double value;
char name[50];
char surname[50];
if ( sscanf( line, "%lf %49s %49s", &value, name, surname ) == 3 )
{
sum += value;
}
else
{
printf( "WARNING: skipping line due to parse failure!\n" );
}
}
return sum;
}
int main( void )
{
//calling this function would also work for an opened file, but
//for simplicity, I am only passing it "stdin"
double sum = get_sum( stdin );
printf( "The sum is: %lf\n", sum );
}
有输入
44.56 john doe
100.21 jane doe
从问题来看,这个程序有以下输出:
The sum is: 144.770000
如果您现在改为向程序提供包含一行无效输入的输入
44.56 john doe
invalid_input_line
100.21 jane doe
它只会在解析无效行时失败,但仍会正确处理其他行:
WARNING: skipping line due to parse failure!
The sum is: 144.770000
如前所述,您的程序能够从此错误中恢复,因为它使用fgets 一次读取一行,并且使用sscanf 而不是fscanf。否则,从此类错误中恢复会更加复杂。