2

I'm having a hard time with a do-while loop, that is supposed to stop when we reach the end of the file. Here's the loop code:

do  {
    if (pcompanyRow[0] != '#' && pass == 1) {
        strtok(pcompanyRow, ":");
        pcompanyName = strcpy(pcompanyName, strtok(NULL, ""));
        pass = 2;
        fgets(pcompanyRow, 1024, f);
    }
    if (pcompanyRow[0] != '#' && pass == 2) {
        strtok(pcompanyRow, ":");
        pcompanySMSPrice = strcpy(pcompanySMSPrice, strtok(NULL , ""));
        pass = 3;
        fgets(pcompanyRow, 1024 , f);
    }
    if (pcompanyRow[0] != '#' && pass == 3) {
        strtok(pcompanyRow, ":");
        pcompanyMMSPrice = strcpy(pcompanyMMSPrice, strtok(NULL, ""));
        pass = 4;
        fgets(pcompanyRow, 1024, f);
    }
    if (pass == 4)  {
        AppendCompanyNode(pcompanyList, pcompanyName, pcompanySMSPrice, pcompanyMMSPrice);
        pass = 1;
    }
} while (!feof(f));

After running with the debugger, I noticed that all the crash problems I have are because it doesn't go out of this loop even when it reached the whole lines.

How should I write it correctly?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
k-man
  • 1,121
  • 5
  • 17
  • 26
  • 2
    As the answers say, the succinct answer is "You don't use feof()". The only time you use 'feof()' is when you get an error-or-eof indication from a primary input function (`fgets()` for example) and you decide that you want to distinguish between EOF and an error. Most often, most people do not bother to distinguish between the two (me specifically, but most of the code I've seen). I don't recall using `feof()` at all - which means I've probably used it a couple of times in the last quarter century of C programming. – Jonathan Leffler Nov 28 '10 at 22:17
  • 1
    @Jonathan: I think it makes a lot more sense to check `ferror(f)` rather than `!feof(f)` if you want to know whether an error occurred. Sometimes `feof` is useful in do-while loops, but I agree it's pretty useless most of the time. – R.. GitHub STOP HELPING ICE Nov 28 '10 at 22:35
  • 1
    @R..: yes, it makes more sense to use `ferror()` than `feof()`, but I confess I don't often use that, either. But I should have said so in my comment - or added a second one since I was running out of space. – Jonathan Leffler Nov 28 '10 at 22:37

3 Answers3

8

You should never use feof() as the exit indicator for a loop. feof() is TRUE only after the end of file (EOF) is read, not when EOF is reached

Source here. It also explains the problem in detail and how to fix it.

Milan
  • 15,389
  • 20
  • 57
  • 65
  • i changed the while to that: while(fgets(pcompanyRow, 1024 , f) != NULL) – k-man Nov 28 '10 at 23:04
  • anyway it wont stop!! i can see the pcompanyRow value, it took again the first line, it bring me the file lines in loop and wont stop...what can i do? – k-man Nov 28 '10 at 23:06
  • 1
    +1, but I question the wording. EOF is never 'read'. A read function may return EOF as a result of encountering end of file, but EOF is not a value that is read. – William Pursell Mar 26 '11 at 13:05
  • The code you had pointed out, shows an extra read being performed because of feof(). I ran the exact same code, i dont get that problem. Any ideas why? – Somjit Dec 13 '14 at 17:24
4

I would change your loop and logic to use this:

while (fgets(pcompanyRow, 1024, f) != NULL) {

    /* do things */

}

when fgets() attempts to read past the end of the file, it will return NULL and you'll break out of the loop. You can still continue to use pass and your other flags/logic, but the conditions you check for will be slightly different.

poundifdef
  • 18,726
  • 23
  • 95
  • 134
0

I suggest use both fgets() and feof(). Last string in file might have \n or might not. If you use only feof(), you can skip (lost) last line.

 for(;;)
 {char *pc;

  pc=fgets(buf,sizeof(buf),fd);

  if(!pc)
    {//it may be read error or end of file
      if(feof(fd))
        {//it is end of file, normal exit from for
         break;      
        }
       else
        {//it is i/o error 
         fclose(fd);
         return 2;
        }
    }
}//for
Andrey My
  • 1
  • 3