Uncatchable flaw in file reading - c

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.

Related

How safe is using !feof in searching a file?

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.

Why is my program perceiving an EOF condition way before my file actually ends?

My code reads line by line from a text file and stores the lines in a massive array of char pointers. When I use an ordinary text file, this works with no issues. However, when I try to read from the 'dictionary.txt' file I'm supposed to be using, my program detects EOF after reading the first of MANY lines in the file.
int i = 0;
while( 1 ) {
size_t size = 50;
fseek( dicFile, 0L, getline( &dictionary[i++], &size, dicFile) );
printf( "%d:\t%s", i, dictionary[i - 1] );
if( feof( dicFile ) ) {
fclose( dicFile );
break;
}
}
puts("finished loading dictionary");
Here is the start of the dictionary file I'm attempting to load:
A
A's
AA's
AB's
ABM's
AC's
ACTH's
AI's
AIDS's
AM's
AOL
AOL's
ASCII's
ASL's
ATM's
ATP's
AWOL's
AZ's
The output is get from this portion of the program is:
1: A
2: finished loading dictionary
Thanks for any help.
Your third argument to fseek() is nuts. I've seen at least one implementation that treated every out of range third argument as SEEK_END. Oops.
You should just call getline() in the loop instead. In fact, just check the return value of getline() for -1 and get rid of that feof().

How to stop reading a txt file at the end of it

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.

Using feof to read until end of file [duplicate]

This question already has answers here:
Why is “while( !feof(file) )” always wrong?
(5 answers)
Closed 5 years ago.
So I have read multiple posts on why feof doesn't work properly and they all utilize using a while(fscanf(...) == 1) to read to end of file, the problem I have is that I have temp values that are different for each loop, because it is reading each line processing it and then moving to next line. The code I currently have reads all the input properly but prints the last line twice. I was wondering if there was a better way to go about this instead of just doing a hack job and removing the last line processed, since it is processed twice.
void readInputFile(Customer customers[]) {
FILE *input = fopen("hw4input.txt", "r");
while (!feof(input)) {
char tempName[MAXNAMELEN];
int tempQuantity;
char tempItem[MAXNAMELEN];
double tempPrice;
fscanf(input, "%s %d %s $%lf", &tempName, &tempQuantity, &tempItem, &tempPrice);
printf("%s %d %s %.2lf\n", tempName, tempQuantity, tempItem, tempPrice);
}
printf("EOF\n");
fclose(input);
}
You cannot use feof() to detect end of file before attempting to read from the file. feof() will return the state of the end-of-file status only after a failed attempt at reading data from the file.
You should instead read values from the stream, with fscanf() for a quick and dirty throw away toy program, or with fgets() for a more robust parser:
void readInputFile(Customer customers[]) {
FILE *input = fopen("hw4input.txt", "r");
if (input != NULL) {
char name[1024];
int quantity;
char item[1024];
double price;
while (fscanf(input, "%1023s %d %1023s %lf", name, &quantity, item, &price) == 4) {
printf("%s %d %s %.2lf\n", name, quantity, item, price);
}
printf("EOF\n");
fclose(input);
} else {
printf("Cannot open input file\n");
}
}
I was wondering if there was a better way to go about this instead of just doing a hack job and removing the last line processed
Yes, there is.
Check the return value from fscanf in your code. The call will fail when you try to read past the end of the file.
You should be checking it anyway. There are even a lot of people who post here who will opine that you shouldn't use any of the *scanf() functions anyway because they're very difficult if not impossible to use in any robust way. There's almost always a way you can feed one of the *scanf() functions data that will cause problems.

feof detecting false end of file

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);

Resources