I'm trying to study the C language and basically what I want to do is read a file and put it into a struct I created, and then later I'll be doing other things with the struct, but I want to get through the first part first. Let's say that I have a text file called captains.txt and the contents are:
picard 95
janeway 90
pike 15
(note that the last line is just 'pike 15')
So I created a program that's like this:
#include <stdio.h>
#include <stdlib.h> //for exit()
#include <string.h>
#include <ctype.h>
struct captain
{
char capName[10];
int number;
};
typedef struct captain captain;
int main()
{
FILE* file = fopen("captain.txt","r");
if (file == NULL)
{
printf("\nerror opening file");
exit(1);
}
else{
printf("\nfile is opened");
}
char buffer[50];
fgets(buffer,50,file);
while (!feof(file))
{
captain c;
sscanf(buffer, "%s %d", &c.capName, &c.number);
printf("\nc captain is: %s %d", c.capName, c.number);
fgets(buffer,50,file);
}
fclose(file);
return 0;
}
The output on my console is
file is opened
c captain is: picard 95
c captain is: janeway 90
Process returned 0 (0x0) execution time : 0.006 s
Press any key to continue.
Hence Captain Pike is missing in space... almost literally because when I add a new line to the text file that it becomes like this:
picard 95
janeway 90
pike 15
(note the newline after 'pike 15')
Then my output becomes correct. So I know that my program doesn't account for the lack of a newline at the end of the file... so how do I solve this?
Compare these two programs, one (mis)using
feof()and one not using it at all. The first corresponds closely to the code in the question — it ignores the return value fromfgets()to its detriment. The second only tests the return value fromfgets(); it has no need to usefeof().eof53.ceof71.cGiven a data file
abccontaining 3 bytes — 0x41 ('A'), 0x42 ('B'), 0x43 ('C') and no newline, I get the following results:This was tested on MacOS Big Sur 11.6.6.
Note that
fgets()does not report EOF (by returning a null pointer) when reading the (only) incomplete line, but empirically,feof()does report EOF — correctly, since the file input has ended, even thoughfgets()did return a string (but not a line) of data.As explained in the canonical Q&A
while (!feof(file))is always wrong!, usingfeof()rather than testing the return value from the I/O functions leads to bad results.