有人可以告诉我fscanf
如何处理这个特定的例子(也就是EOF所代表的)。代码有效,但我不理解它背后的过程。
#include <stdio.h>
#include <stdlib.h>
#define LEN 20
int main()
{ FILE *in;
float average;
char name[LEN];
char surname[LEN];
int grade, n_grades; //n_grades is the total number of grades a person has//
in = fopen("grades.txt","r");
if(in == NULL){
fprintf(stderr,"error fopen(): Failed to open file grades.txt.\n");
exit(EXIT_FAILURE);
}
while(fscanf(in,"%s",name) != EOF){
fscanf(in,"%s",surname);
n_grades = 0;
average = 0.0;
while( !feof(in) && fscanf(in,"%d",&grade)>0 ){
n_grades++;
average += grade;
}
if(n_grades >0)
average /= n_grades;
printf("%s %s %.2f\n", name, surname, average);
}
fclose(in);
return 0;
}
grades.txt
看起来像这样:
Steve Stevenson 2 9 4 3 2
John Johnson 2 11 5 3
Jack Jacskon 22 1 4 5
我不明白这个while
循环是如何工作的。 fscanf
如何准确知道何时读入哪个字符串?它是如何知道一行的结束时间以及如何进行下一行的?
答案 0 :(得分:3)
你必须专注于你在那里的双循环:
while(fscanf(in,"%s",name) != EOF){
fscanf(in,"%s",surname);
while( !feof(in) && fscanf(in,"%d",&grade)>0 ){
n_grades++;
}
}
EOF代表End Of File,因此第一个循环将继续,直到找到文件的末尾,即直到文件指针到达文件末尾。
现在请记住,您的文件包含以下数据:Steve Stevenson 2 9 4 3 2
。
因此,第一次尝试读取名称,如果尚未达到EOF,则表示您读取了一个名称并在name
中分配了该名称。在这里你读史蒂夫。
现在这个fscanf(in,"%s",surname);
将读取文件in
中当前行的第二个字符串指向(注意%s
,这表示我们希望读取一个字符串)。您阅读史蒂文森并将其分配给surname
。
然后,在第二段时间,您阅读,直到您不到达EOF AND ,直到您读取整数。如果您查看fscanf()的参考号,您会看到:
返回值 成功时,该函数返回成功填充的参数列表的项数。由于匹配失败,读取错误或文件结束的范围,此计数可以匹配预期的项目数或更少(甚至为零)。
如果在读取时发生读取错误或达到文件结尾,则设置正确的指示符(feof或ferror)。并且,如果在成功读取任何数据之前发生任何一次,则返回EOF。
因此,当您读取换行符时,您将读取零整数,因此您将退出循环。
这样你最终会解析所有文件。
根据here与scanf()
的示例精神,您可以重新编写代码:
while(fscanf(in,"%19s",name) != EOF) {
为了避免溢出。这里20是你的数组的大小。
答案 1 :(得分:1)
fscanf()
的原型是
int fscanf(FILE *stream, const char *format, ...)
在您的代码中
fscanf(in,"%s",name)
因此格式说明符确保文件中的第一个字符串被读取为name。我希望你知道在遇到空格之前%s
如何工作。
现在文件指针指向文件中的下一个字符串,下一个字符串的读取方式与surname
类似,然后我们继续查看字符串后面的整数。
fscanf(in,"%d",&grade);
请注意,fscanf()
会返回成功扫描的项目数,当出现错误或EOF时返回EOF。
答案 2 :(得分:0)
你可以把fscanf看成是一个函数,它根据第三个参数是从文件而不是键盘输入的。如果是标准输入则需要键盘输入。当从文件中读取空间字符时,它会停止并返回它已读取的字符,直到空格。