I read here that feof or more precisely using !feof in searching for a info in a file is a bad habit.
What I understood is that it's bad because it reads information from the FILE pointer before called function or process or something like that.
Wouldn't it be fine to have a do/while loop with fscanf inside and !feof as the exit condition?
This is a search function that I did:
typedef struct
{
char lname[20] , fname[20];
int nchildren;
}employee;
void searchemployee(char *filename , char *str)
{
employee e;
FILE *f;
int c;
f = fopen(filename, "r");
if (f == NULL)
printf("file couldn't be loaded\n");
else {
c = 0;
do {
fscanf(f, "%s %s %d\n", e.fname, e.lname, &e.nchildren);
if (strcmp(e.fname, str) == 0)
c = 1;
} while (c == 0 && !feof(f));
if (c != 1)
printf("employee not found\n");
else
printf("employee : %s %s| children : %d\n", e.fname, e.lname, e.nchildren);
}
fclose(f);
}
The return value of the function feof specifies whether a previous input operation has already encountered the end of the file. This function does not specify whether the next input will encounter the end of the file.
The problem with
do{
fscanf(f,"%s %s %d\n",e.fname,e.lname,&e.nchildren);
if (strcmp(e.fname,str)==0)
c=1;
}while(c==0 && !feof(f));
is that if fscanf fails and returns EOF due to encountering the end of the file, then it will write nothing to e.fname.
If this happens in the first iteration of the loop, then the content of e.fname will be indeterminate and the subsequent function call strcmp(e.fname,str) will invoke undefined behavior (i.e. your program may crash), unless e.fname happens to contain a terminating null character.
If this does not happen in the first iteration, but rather in a subsequent iteration of the loop, then the content of e.fname will contain the content of the previous loop iteration, so you will effectively be processing the last successful call of fscanf twice.
In this specific case, processing the last successful call of fscanf twice is harmless, except for being a slight waste of CPU and memory resources. However, in most other cases, processing the last input twice will result in the program not working as intended.
See the following question for further information:
Why is “while( !feof(file) )” always wrong?
If you change the loop to
for (;;) {
fscanf(f,"%s %s %d\n",e.fname,e.lname,&e.nchildren);
if ( c != 0 || feof(f) )
break;
if (strcmp(e.fname,str)==0)
c=1;
}
so that the loop condition is checked in the middle of the loop, then the problem mentioned above will be gone.
However, it is generally better to check the return value of fscanf instead of calling feof, for example like this:
c = 0;
while ( c == 0 && fscanf(f,"%s %s %d\n",e.fname,e.lname,&e.nchildren) == 3 ) {
if (strcmp(e.fname,str)==0)
c=1;
}
Also, you don't need the flag variable c. I suggest that you incorporate the lines
if (c!=1)
printf("emplyee not found\n");
else
printf("employee : %s %s| children : %d\n",e.fname,e.lname,e.nchildren);
partially into the loop, like this:
void searchemployee( char *filename, char *str )
{
employee e;
FILE *f = NULL;
//attempt to open file
f = fopen( filename, "r" );
if ( f == NULL )
{
printf( "file couldn't be loaded\n" );
goto cleanup;
}
//process one employee record per loop iteration
while ( fscanf( f, "%s %s %d\n", e.fname, e.lname, &e.nchildren ) == 3 )
{
//check whether we found the target record
if ( strcmp(e.fname,str) == 0 )
{
printf(
"employee : %s %s| children : %d\n",
e.fname, e.lname, e.nchildren
);
goto cleanup;
}
}
printf( "employee not found.\n");
cleanup:
if ( f != NULL )
fclose(f);
}
Another issue is that when using %s with scanf or fscanf, you should generally also add a width limit, to prevent a possible buffer overflow. For example, if e.fname has a size of 100 characters, you should use %99s to limit the number of bytes written to 99 plus the terminating null character.
Calling feof asks the question “Was end-of-file or an error encountered in a previous operation on this stream?”
If you use feof to answer that question, that is fine. But, you use feof to expect that your next operation will read data from the file, that is wrong. The previous operation might have ended just before the end of the file, so feof says “no,” but there is nothing left in the file to read.
The file/stream functions in the standard C library are designed to tell you when they failed because end-of-file was reached. You should use the return value (or other indication) provided by each function to test for a problem:
if (3 != fscanf(f, "%s %s %d\n", e.fname, e.lname, &e.nchildren))
{
// Handle fact that fscanf did not read and convert 3 values.
}
int x = getchar();
if (x == EOF)
{
// Handle fact that fscanf did not read and convert 3 values.
}
Note that calling fscanf and then feof will tell if fscanf encountered end-of-file or an input error, but it will not tell you whether fscanf read some input and assigned some values but then encountered end-of-file and did not finish. If you are reading only one thing, you might get away with fscanf followed by feof, but a more sophisticated program may need to distinguish partial inputs.
Related
I have a question about I/O in C language, how can I make a difference to know if the lecture of my file has ended or if the data can't be read (or has a problem) as in the both cases, fscanf returns EOF ?
Don´t rely only on the return value of fscanf(), rely beside this one on feof() and ferror() after the call to fscanf():
FILE* file;
if((file == fopen("file.txt","r")) == NULL)
{
fprintf(stderr, "File could not be opened!");
return EXIT_FAILURE;
}
char buf;
/******************************************************************************/
while(fscanf(file,"%c",buf) == 1) { // checks if an error was happen, else
// iterate to catching characters.
/* handling of read character */
}
if(ferror(file)) // checks if an I/O error occurred.
{
// I/O error handling
fprintf(stderr,"Input/Output error at reading file!");
clearerr(file);
// Further actions
}
else if(feof(file)) // checks if the end of the file is reached.
{
// end of file handling
fprintf(stderr,"Reached End of File!");
clearerr(file);
// Further actions
}
/******************************************************************************/
if(fclose(file) != 0)
{
fprintf(stderr, "File could not be closed properly!");
return EXIT_FAILURE;
}
As per fscanf() return value:
ISO/IEC 9899:2017
§ 7.21.6.2 - 16 - The fscanf function returns the value of the macro EOF if an input failure occurs before the first conversion (if any) has completed. Otherwise, the function returns the number of input items assigned, which can be fewer than provided for, or even zero, in the event of an early matching failure.
EOF is a macro with the value of -1, by itself it's not distinguishable as for the reasons why it occurs.
For this distinction § 7.21.6.2 - 19 recommends the use of feof() for end-of-file and ferror() for I/O error:
EXAMPLE 3 To accept repeatedly from stdin a quantity, a unit of measure, and an item name:
#include<stdio.h>
/*...*/
int count; floatquant;
charunits[21], item[21];
do {
count = fscanf(stdin, "%f%20sof%20s", &quant, units, item);
fscanf(stdin,"%*[^\n]");
} while(!feof(stdin) && !ferror(stdin));
My usual approach when reading formated input, is to check the inputed values. For a sample input of 2 integers you can do something like:
int a, b;
FILE* file;
//open file to read
while(fscanf(file, "%d %d", &a, &b) == 2){ //read each 2 integers in the file, stop when condition fails, i.e. there are nothing else to read or the read input is not an integer
//...handle inputs
}
This kind of read is safe and addresses all failure scenarios since it works for bad input and for "end of file".
I'm writing a C program which reads a text file line by line with a certain format to it.
I made a do { ... } while(!feof(file)); loop but it always loops one too many times. This is an issue because I have made it so that when my program expects to read something but gets nothing, it throws an error, so now it is throwing an error every time because it reaches the end of the file at the top of my loop.
I figured this is because the eof flag is triggered only once you try to fscanf something but there is nothing there. How can I fix this problem? Putting a final fscanf at the bottom doesn't work because if it's not at the end of the file, it will mess all the readings up and shift everything by one.
do {
read = fscanf(/*...*/);
if (read != 1)
{
return -1;
}
// Read grades
read = fscanf(/*...*/);
if (read != 3)
{
return -1;
}
// Read student kind
int student_kind = 0;
read = fscanf(/*...*/);
if (read != 1)
{
return -1;
}
if (student_kind < 0 | student_kind > 2)
{
printf("Invalid student kind");
return -1;
}
SCIPER sciper_teammate = 0;
read = fscanf(/*...*/);
if (read != 1)
{
return -1;
}
} while (!feof(file));
Since you are using fscanf():
ISO/IEC 9899:2017
§ 7.21.6.2 - 16 - The fscanf function returns the value of the macro EOF if an input failure occurs before the first conversion (if any) has completed. Otherwise, the function returns the number of input items assigned, which can be fewer than provided for, or even zero, in the event of an early matching failure.
EOF is a macro with the value of -1, by itself it's not distinguishable as for the reasons why it occurs.
For this distinction § 7.21.6.2 - 19 recommends the use of feof() for end-of-file and ferror() for I/O error:
EXAMPLE 3 To accept repeatedly from stdin a quantity, a unit of measure, and an item name:
#include<stdio.h>
/*...*/
int count; floatquant;
charunits[21], item[21];
do {
count = fscanf(stdin, "%f%20sof%20s", &quant, units, item);
fscanf(stdin,"%*[^\n]"); //here discarding unread characters in the buffer
} while(!feof(stdin) && !ferror(stdin));
This should work in your case but personaly. I don't like this approach since if you input less values than what fscanf is expecting this will fail, normaly resulting in an infinite loop.
My approach when reading formated input, is to check the inputed values.
For a sample input of 2 integers you can do something like:
Live sample
#include <stdio.h>
int main()
{
int a, b;
FILE* file;
if(!(file = fopen("file.txt", "r"))){
return 1;
}
while(fscanf(file, "%d %d", &a, &b) == 2){ //read each 2 integers in the file, stop when condition fails, i.e. there are nothing else to read or the read input is not an integer
printf("%d %d\n", a, b);
}
}
This addresses all input failures and will end the cycle for I/O error, for EOF and for bad inputs.
Can anyone tell me the flaw in this program...? Actually it is printing the last record twice.
#include <stdio.h>
int main(void)
{
int accountNum;
char name[30];
double balance;
int counter = 0;
FILE *clientDataFile1;
if( (clientDataFile1 = fopen("clients.txt", "r")) == NULL )
printf("File could not be opened");
else
{
printf("%-10s %-13s %s\n", "Account", "Name", "Balance");
while( !feof(clientDataFile1) )
{
fscanf(clientDataFile1, "%d%s%lf", &accountNum, name, &balance);
printf( "%-10d%-13s%.2lf\n", accountNum, name, balance );
}
printf("\n\n\n");
rewind(clientDataFile1);
counter++;
fclose(clientDataFile1);
}
return 0;
}
This is getting really painful.I tried many times but the flaw was uncatchable. Either the working is not clear to me or Ubuntu 12.10 or gcc is responsible for this.
Help me....
You're using feof() in a manner which seems very popular by beginners, but unfortunately is still wrong.
The point of feof() is to query, after an I/O error has occurred, if it occured because end of file had been reached. It should not be used to prematurely decide if the file has ended.
Just do the read until it fails.
while( fscanf(clientDataFile1, "%d%s%lf", &accountNum, name, &balance) == 3 )
{
printf( "%-10d%-13s%.2lf\n", accountNum, name, balance );
}
After reading the answer from #unwind, I got curious as to what feof() does, and why this causes the double-print of the last record.
From cplusplus.com: "Notice that stream's internal position indicator may point to the end-of-file for the next operation, but still, the end-of-file indicator may not be set until an operation attempts to read at that point."
So you're reaching EOF, and printing the last record, but the flag that feof() checks hasn't been set yet. Then, on the next iteration of the loop you do a fscanf which fails due to being past EOF. This failure causes the flag to be set, making this the last iteration of the loop. This iteration still prints what is already saved in the accountnum, name, and balance variables, thus you see the last record twice.
Short answer: your while loop should look like this :
while (!feof(clientDataFile1))
{
if (EOF == fscanf(clientDataFile1, "%d%s%lf", &accountNum, name, &balance))
break ;
printf( "%-10d%-13s%.2lf\n", accountNum, name, balance );
}
while( fscanf(clientDataFile, "%d%s%lf", &accountNum, name, &balance) != EOF )
printf( "%-10d%-13s%.2lf\n", accountNum, name, balance);
Actually value of EOF is -1 and fscanf() returns the number of inputed variables. So, expression != evaluates 0 when value of fscanf() is equal to EOF which is -1 and hence the break in while is achieved.
I asked a different question about this earlier, but I was way off base about the problem so I've created a new question as I'm asking an entirely different question.
I have a function that reads a given line in a text file (given by ac variable). It performs the read of the line and then checks if that was the last line in the file. If so it increments a value.
The problem is that it's incremented the value even when it's not the actual end of the file. I think I'm using feof wrong but I've had no luck getting it to work:
int readIn(TinCan* inCan, int toggle)
{
int ii, isFinished = 0;
char fullName[20];
sprintf(fullName, "Label_%d.txt", inCan->pid);
FILE* fp;
fp = fopen(fullName, "r");
if(fp==NULL)
{
printf("Error: could not open %s\n", fullName);
}
else
{
for (ii=0; ii < ((inCan->ac)-1); ii++)
{
fscanf(fp, "%*d %*d %*d\n"); /*move through lines without scanning*/
}
fscanf(fp,"%d %d %d", &inCan->ac, &inCan->state, &inCan->time);
}
if (feof(fp) && (toggle == 1))
{
printf("File ended");
writeLog(inCan);
isFinished = 1;
terminated++;
}
fclose(fp);
return finished;
}
Sample data as requested, this is a text file I may use:
1 1 30
2 2 5
3 1 1
fscanf correctly assigns the values. On the second line, feof returns true and terminated is incremented. feof returns true again for the 3rd line and increments terminated a second time.
feof() does not detect if the file has ended. It detects if the last read error was due to the file having ended.
feof() only happens after a failed read.
So, first read data and check the return value. If the read failed use feof() to make sure it failed because the END-OF-FILE was reached (other reasons for the read to fail are error of some kind (network down, bad sector, printer on fire, ...), detectable with ferror()).
It's hard to tell without knowing the data format, but
fscanf(fp,"%d %d %d", &inCan->ac, &inCan->state, &inCan->time);
will read 3 values, but on the last line, it won't have read the end of line character, so it's not the end of the file.
Try:
fscanf(fp,"%d %d %d\n", &inCan->ac, &inCan->state, &inCan->time);
While doing filing im stuck here.The condition of the while loop is not working.The compiler says cannot convert int to FILE*.
while(pFile!=EOF);
Should i typecase the pFile to int?I tried that but it did not worked.Thanks in advance.
The complete code is:
int main()
{
char ch;
char name[20];
FILE *pFile;
int score;
pFile=fopen("database.txt","r");
if(pFile!=NULL)
{
while(pFile!=EOF);
{
fscanf(pFile,"%c",ch);
}
}
else
printf("Cant open the file.......");
fclose(pFile);
return 0;
}
First, you do not want to use while (!feof(pFile)) -- ever! Doing so will almost inevitably lead to an error where the last data you read from the file appears to be read twice. It's possible to make it work correctly, but only by adding another check in the middle of the loop to exit when EOF is reached -- in which case, the loop condition itself will never be used (i.e., the other check is the one that will actually do the job of exiting the loop).
What you normally do want to do is check for EOF as you read the data. Different functions indicate EOF in different ways. fgets signals failure (including EOF) by returning NULL. Most others (getc, fgetc, etc.) do return EOF, so you typically end up with something like this:
int ch; // Note, this should be int, NOT char
while (EOF != (ch=getc(pFile)))
process(ch);
or:
char buffer[MAX_LINE_SIZE];
while (fgets(buffer, sizeof(buffer), pFile))
process(buffer);
With scanf, checking for success is a little more complex -- it returns the number of successful conversions, so you want to make sure that matches what you expected. For example:
while (1 == fscanf(fPfile, "%d", &input_number))
process(input_number);
In this case I've used 1 because I specified 1 conversion in the format string. It's also possible, however, for conversion to fail for reasons other than EOF, so if this failes, you'll frequently want to check feof(pFile). If it returns false, do something like reading the remainder of the line, showing it to the user in a warning message, and then continuing to read the rest of the file.
It depends what pFile and EOF are defined as, but I will asssume that pFile is a *FILE, and EOF is from stdio.h. Then I guess you should do something like:
#include <stdlib.h>
#include <stdio.h>
#define FILENAME "file.txt"
int main(void) {
FILE *pFile;
int ch;
pFile = fopen(FILENAME,"r");
if (pFile) {
while ((ch = getc(pFile)) != EOF) {
printf("Read one character: %c\n", ch);
}
close(pFile);
return EXIT_SUCCESS;
} else {
printf("Unable to open file: '%s'\n", FILENAME);
return EXIT_FAILURE;
}
}
which yields
$ echo "abc" > file.txt
$ /tmp/fileread
Read one character: a
Read one character: b
Read one character: c
Read one character:
# last character being a linefeed
Assuming pFile is your file handle, this doesn't change as you read from the file. EOF is returned by e.g. fgetc(). See e.g. http://www.drpaulcarter.com/cs/common-c-errors.php#4.2 for common ways to solve this.
here is correct way:
c = getc(pFile);
while (c != EOF) {
/* Echo the file to stdout */
putchar(c);
c = getc(pFile);
}
if (feof(pFile))
puts("End of file was reached.");
else if (ferror(pFile))
puts("There was an error reading from the stream.");
else
/*NOTREACHED*/
puts("getc() failed in a non-conforming way.");
fclose(pFile);
pFile is a pointer to a file. EOF is usually defined as -1, a signed integer.
What you should do is fopen, make sure pFile != NULL, then call some function on the file handle until that function returns EOF. A pointer will (or rather, should) never be EOF. But a function acting on that pointer may return EOF.
I'm guessing you want to keep looping while you haven't hit end-of-file. In that case, you are looking for this:
while (!feof(pFile))
{
...
}
That said, this is still not quite correct. feof will only return true once it tries to read beyond the end of the file. This means feof can return false and yet there is no more data to read. You should really try your operation and only check for end of file if it fails:
char buffer[SIZE];
while (fgets(buffer, sizeof(buffer), pFile))
{
...
}
if (!feof(pFile))
{
// fgets failed for some reason *other* then end-of-file
}