Reputation: 462
This is a function that reads an unknown number of integers from a file and calculates the average. For some reason the last element in the file is being read twice. Can someone please explain why? I know how to fix it but would like to know what goes on behind the scenes.
int total = 0, count = 0, input;
FILE *filePtr;
filePtr = fopen("file.txt", "r");
if (filePtr != NULL)
do
{
fscanf(filePtr, "%d", &input);
total = total + input;
count++;
} while (!feof(filePtr));
printf ("%d", total);
I fixed it by putting a second if
in the loop:
do
{
fscanf(filePtr, "%d", &input);
if (!feof(filePtr))
{
total = total + input;
count++;
}
} while (!feof(filePtr));
Upvotes: 2
Views: 5397
Reputation: 5784
from feof documentation: "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 even if you read the last int in the file the pointer indicates to EOF, but because no one attempted to read again feof does not indicate that the file end is reached.
I think that the same value is 'read twice' because the variable is not changed and it holds the same value as the last one read.
Upvotes: 1
Reputation: 3396
The do-while
structure cause this side effect, because it first reads the data, so the condition is checked just after the code inside the loop is executed. Try to use the while
structure to avoid reading the last item twice, you will no longer need to do the if
test inside the loop.
while (!feof(filePtr)){
fscanf(filePtr, "%d", &input);
total = total + input;
count++;
}
Upvotes: 1
Reputation: 24577
You're not checking that fscanf
actually finds a number. The last call will fail because you're most likely just reading in the last line break in the file.
Try this:
do
{
if (fscanf(filePtr, "%d", &input)==1) {
total = total + input;
count++;
}
} while (!feof(filePtr));
EDIT: @Andrew is right — you should really check for an EOF at the top of the loop:
while (!feof(filePtr)) {
/* ... */
}
Upvotes: 3
Reputation: 10507
It looks like you shouldn't use a do-while loop
. Basically, you're reading from the file THEN checking for end of file. What if there are 0 ints
? You'll try reading BEFORE you check to see if the file is at the end.
Also, you're not checking the result of fscanf
. It reports if it was successful or not...
Upvotes: 3