-1

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));
anastaciu
  • 23,467
  • 7
  • 28
  • 53
2000mroliver
  • 135
  • 1
  • 9
  • 5
    Does this answer your question? [Why is “while ( !feof (file) )” always wrong?](https://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong) – RamblinRose Mar 21 '20 at 13:39
  • 2
    You can use the return value from `fscanf ` to control the loop. `while(fscanf(...) == expectedNumberOfItems) {...}`. Anyway, you should *always* check the return value from the `scanf` function family. – Weather Vane Mar 21 '20 at 13:46
  • Vote for reopen because the subject of the question is a read operation inside a `do-while` loop, not a `while-loop`. Which makes a difference to the provided duplicate. – RobertS supports Monica Cellio Mar 21 '20 at 14:01
  • @exnihilo for me the duplicate is not relevant because it is about to use _feof_ **before** any read. Agree the right way is to check the result of any read, using _while(fscanf(...) == ...) ..._ if possible as proposed by WeatherVane or something like _for () { ... if (fscanf(...) != ...) break; ... }_ ofc – bruno Mar 21 '20 at 14:36
  • @exnihilo We don't know what the OP meant with that statement and the whole expression of the question itself exactly. That is a big problem. I agree, the question should be closed for "needs more focus". – RobertS supports Monica Cellio Mar 21 '20 at 14:43
  • We don't know what the OP is doing without seeing the code. – Jongware Mar 21 '20 at 15:09
  • Sorry for being unresponsive, so as requested I put up my code (changed/removed some irrelevant stuff to make it shorter / not get in trouble if my school finds my code online or something) Anyways I think I know how to solve my problem, as many suggested by using a if(fscanf(...) !=) intead of a do while loop, but I would have to scan everything in one go and wouldn't be able to put specific error messages. – 2000mroliver Mar 21 '20 at 16:30

1 Answers1

0

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.

anastaciu
  • 23,467
  • 7
  • 28
  • 53