feof usage

M

Mantorok Redgormor

My professor that teaches C says that using feof to test if EOF is
reached while using a function like fgets on a file is okay. but i've
been told elsewhere that it is not okay. what is the case here? is it
okay or not?




nethlek
 
A

Artie Gold

Mantorok said:
My professor that teaches C says that using feof to test if EOF is
reached while using a function like fgets on a file is okay. but i've
been told elsewhere that it is not okay. what is the case here? is it
okay or not?
It's OK -- but feof() only returns a non-zero (`true') value *after*
an attempted `read' has failed.

HTH,
--ag
 
M

Mac

My professor that teaches C says that using feof to test if EOF is
reached while using a function like fgets on a file is okay. but i've
been told elsewhere that it is not okay. what is the case here? is it
okay or not?

The issue is that feof() only tells you AFTER you have attempted to read
past the end of the file. If you understand that, and code accordingly, it
is OK to use it, AFAIK.

That is, if a file has n characters, you can read all of them with fgets
and feof() will still return zero (false). But if you try to read n+1,
then fgets will still succeed, but feof() will return non-zero (true).

HTH

Mac
--
 
J

Jack Klein

My professor that teaches C says that using feof to test if EOF is
reached while using a function like fgets on a file is okay. but i've
been told elsewhere that it is not okay. what is the case here? is it
okay or not?

This is covered in the FAQ, specifically at
http://www.eskimo.com/~scs/C-faq/q12.2.html

Generally it is not a good idea to use feof() this way. It is not so
bad if you test for EOF after an input operation and before trying to
use the input data. But it can still cause problems, because an error
does not cause feof() to return a non-zero value.

There are all kinds of things that can cause an error in a file
operation. Hard drives are pretty reliable these days, but they are
still wear parts. Or a user could remove the media containing a file,
such as a floppy disk or CD. Or the network connection could go down.

All functions that can read from a file return a value that indicates
whether they succeeded or failed. fgets() returns the pointer you
passed it if it succeeded, or a null pointer if it failed. So to use
fgets() in a loop:

while (NULL != fgets(buffer, sizeof buffer, file_ptr))
{
/* ... */
}

After your input function indicates a failure, you can use feof() and
ferror() to determine whether you successfully read the entire file or
whether an error occurred.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++ ftp://snurse-l.org/pub/acllc-c++/faq
 
M

Martin Ambuhl

Mantorok said:
My professor that teaches C says that using feof to test if EOF is
reached while using a function like fgets on a file is okay. but i've
been told elsewhere that it is not okay. what is the case here? is it
okay or not?

Sure, it's OK. But it is useless until EOF has already been reached, by
which time whatever you are using to read the file (fgets, fgetc, fread,
even fscanf) has already given an error indication. feof can be used to
sort out what kind of input error it was. You don't reach EOF on a read
that completely succeeds, so feof is useless then.
 
G

Glen Herrmannsfeldt

Mantorok Redgormor said:
My professor that teaches C says that using feof to test if EOF is
reached while using a function like fgets on a file is okay. but i've
been told elsewhere that it is not okay. what is the case here? is it
okay or not?

Most users of feof() have previously used Pascal, where it is required to
use feof() before reading to avoid a fatal error.

C requires an attempt to read past the end of file before feof() will
indicate it, so direct translation of Pascal feof() to C's feof() tend to
fail.

All C input functions signal the failure to do what they were asked to do,
and that tends to be a better way to do the test.

-- glen
 
M

Mac

Sure, it's OK. But it is useless until EOF has already been reached, by
which time whatever you are using to read the file (fgets, fgetc, fread,
even fscanf) has already given an error indication. feof can be used to
sort out what kind of input error it was. You don't reach EOF on a read
that completely succeeds, so feof is useless then.

Actually, fgets doesn't provide error notification on reaching the end of
a file unless it wasn't able to read any characters, in which case it
returns NULL. It also returns NULL if there is an error reading from the
file.

Apart from that I agree with you. It seems that feof() is seldom useful,
except to distinguish between end of file and some other file error after
the fact.

Mac
--
 
L

LibraryUser

Mac said:
The issue is that feof() only tells you AFTER you have attempted
to read past the end of the file. If you understand that, and
code accordingly, it is OK to use it, AFAIK.

That is, if a file has n characters, you can read all of them with
fgets and feof() will still return zero (false). But if you try to
read n+1, then fgets will still succeed, but feof() will return
non-zero (true).

Correction - that final fgets call will not succeed, it will
return NULL. This may describe either the end-of-file, or a read
error. feof() allows you to disambiguate them.
 
L

LibraryUser

Glen said:
Most users of feof() have previously used Pascal, where it is
required to use feof() before reading to avoid a fatal error.

C requires an attempt to read past the end of file before feof()
will indicate it, so direct translation of Pascal feof() to C's
feof() tend to fail.

All C input functions signal the failure to do what they were
asked to do, and that tends to be a better way to do the test.

The reason for the difference is that Pascal input is always
buffered, so that a look ahead can be implemented by examining
f^. In C, such lookahead involves the use of ungetc() and the
user needs to be highly aware of what is going on. In Pascal
OTOH use of the buffering can cause problems with interactive
input, leading to so-called lazy-io schemes, which in turn
require the user to be aware when using eof and eoln calls.

Neither scheme is perfect, but the trade-offs are different.
 
G

Glen Herrmannsfeldt

LibraryUser said:
The reason for the difference is that Pascal input is always
buffered, so that a look ahead can be implemented by examining
f^. In C, such lookahead involves the use of ungetc() and the
user needs to be highly aware of what is going on. In Pascal
OTOH use of the buffering can cause problems with interactive
input, leading to so-called lazy-io schemes, which in turn
require the user to be aware when using eof and eoln calls.

Interactive input can be confusing in C, too.
Neither scheme is perfect, but the trade-offs are different.

Using the assumptions of one language in programming the other tends to show
those trade-offs.

-- glen
 
M

Mac

Correction - that final fgets call will not succeed, it will
return NULL. This may describe either the end-of-file, or a read
error. feof() allows you to disambiguate them.

I may not have expressed myself as clearly as I could have. The bottom
line, though, is that fgets will not return NULL if it reads a few
characters and THEN encounters eof. It will return NULL when it encounters
the end of the file without reading any characters into the buffer. Unless
I am reading the standard wrong, which is certainly possible.

Mac
--
 
L

LibraryUser

Mac said:
I may not have expressed myself as clearly as I could have. The
bottom line, though, is that fgets will not return NULL if it
reads a few characters and THEN encounters eof. It will return
NULL when it encounters the end of the file without reading any
characters into the buffer. Unless I am reading the standard
wrong, which is certainly possible.

The following covers fgets(). There is an additional provision
somewhere that states that action on final file lines without a
\n termination is undefined or implementation defined.

From N869:

7.19.7.2 The fgets function

Synopsis

[#1]
#include <stdio.h>
char *fgets(char * restrict s, int n,
FILE * restrict stream);

Description

[#2] The fgets function reads at most one less than the
number of characters specified by n from the stream pointed
to by stream into the array pointed to by s. No additional
characters are read after a new-line character (which is
retained) or after end-of-file. A null character is written
immediately after the last character read into the array.

Returns

[#3] The fgets function returns s if successful. If end-of-
file is encountered and no characters have been read into
the array, the contents of the array remain unchanged and a
null pointer is returned. If a read error occurs during the
operation, the array contents are indeterminate and a null
pointer is returned.

____________________

232An end-of-file and a read error can be distinguished by
use of the feof and ferror functions.
 
I

Irrwahn Grausewitz

LibraryUser said:
Mac wrote:

The following covers fgets(). There is an additional provision
somewhere that states that action on final file lines without a
\n termination is undefined or implementation defined.

If this is correct, it would render fgets() almost useless for working
on RealWorld(tm) files. May I kindly ask you where I can find the text
you are referring to?
From N869:

7.19.7.2 The fgets function

Synopsis

[#1]
#include <stdio.h>
char *fgets(char * restrict s, int n,
FILE * restrict stream);

Description

[#2] The fgets function reads at most one less than the
number of characters specified by n from the stream pointed
to by stream into the array pointed to by s. No additional
characters are read after a new-line character (which is
retained) or after end-of-file. A null character is written
immediately after the last character read into the array.

Returns

[#3] The fgets function returns s if successful. If end-of-
file is encountered and no characters have been read into
the array, the contents of the array remain unchanged and a
null pointer is returned. If a read error occurs during the
operation, the array contents are indeterminate and a null
pointer is returned.

IMO this implies that, as long as no error occured and at least one
character has been read so far, fgets() returns a pointer to the
buffer containing what have been read so far plus a terminating '\0'
as soon as it encounters '\n' or EOF.

Regards,

Irrwahn
 
P

pete

Irrwahn said:
If this is correct, it would render fgets() almost useless for working
on RealWorld(tm) files.
May I kindly ask you where I can find the text
you are referring to?

N869
7.19.2 Streams
[#2] A text stream is an ordered sequence of characters
composed into lines, each line consisting of zero or more
characters plus a terminating new-line character. Whether
the last line requires a terminating new-line character is
implementation-defined.
 
B

Barry Schwarz

Irrwahn said:
If this is correct, it would render fgets() almost useless for working
on RealWorld(tm) files.
May I kindly ask you where I can find the text
you are referring to?

N869
7.19.2 Streams
[#2] A text stream is an ordered sequence of characters
composed into lines, each line consisting of zero or more
characters plus a terminating new-line character. Whether
the last line requires a terminating new-line character is
implementation-defined.

That makes the requirement for a final '\n' in the stream
implementation specific. It in no way implies that fgets has any
flexibility on how it process the final line. fgets is required to

read at most n-1 bytes
stop after reading and retaining an '/n' or after reaching eof
return the array address in all cases except
eof encountered without transferring any data
a read error occurs

Nowhere in the standard is any implementation-defined or undefined
behavior specifically described for fgets. This includes the case
where the stream does not terminate with a '\n', whether required to
or not.

One could argue that if the implementation requires the final '\n' in
the stream and it is not present then attempting to read this line
invokes undefined behavior because the stream is not well formed. But
that has nothing to do with fgets and should apply equally to any I/O
function attempting to read the stream.


<<Remove the del for email>>
 
R

Richard Bos

pete said:
Irrwahn said:
If this is correct, it would render fgets() almost useless for working
on RealWorld(tm) files.
May I kindly ask you where I can find the text
you are referring to?

N869
7.19.2 Streams
[#2] A text stream is an ordered sequence of characters
composed into lines, each line consisting of zero or more
characters plus a terminating new-line character. Whether
the last line requires a terminating new-line character is
implementation-defined.

And note that this is true for all <stdio.h> functions, not just for
fgets(). It this requirement applies to your system, it'll be true for
all programs, and you'll be used to it.
All the same, it's best practice to always write the newline anyway, if
only to avoid the following syndrome:

This is a program which doesn't terminate its last line with a
#_wline.

Richard
 
I

Irrwahn Grausewitz

Barry Schwarz said:
N869
7.19.2 Streams
[#2] A text stream is an ordered sequence of characters
composed into lines, each line consisting of zero or more
characters plus a terminating new-line character. Whether
the last line requires a terminating new-line character is
implementation-defined.

That makes the requirement for a final '\n' in the stream
implementation specific. It in no way implies that fgets has any
flexibility on how it process the final line. fgets is required to

read at most n-1 bytes
stop after reading and retaining an '/n' or after reaching eof
return the array address in all cases except
eof encountered without transferring any data
a read error occurs

Nowhere in the standard is any implementation-defined or undefined
behavior specifically described for fgets. This includes the case
where the stream does not terminate with a '\n', whether required to
or not.

Goodness, what a relief! I was already worrying about having to rewrite
all the code that makes use of fgets().

<SNIP>

Irrwahn
 
P

Peter Nilsson

Barry Schwarz said:
Nowhere in the standard is any implementation-defined or undefined
behavior specifically described for fgets.

That's not quite true. There are certainly explicit requirements for the
arguments passed to fgets(), lest UB occur.
This includes the case
where the stream does not terminate with a '\n', whether required to
or not.

I prefer to think the behaviour on reading the last line of text is
implementation defined.
One could argue that if the implementation requires the final '\n' in
the stream and it is not present then attempting to read this line
invokes undefined behavior because the stream is not well formed.

I don't disagree, but sanity would dictate that there's no need to lump
fgets() into the same basket as gets().

[Aside: Dealing with null bytes via fgets() is much trickier than trailing
newlines. Throw in non-sticky EOF and ...]
But that has nothing to do with fgets and should apply equally to any I/O
function attempting to read the stream.

ITYM: that is not specific to fgets...
 
C

Clifton Liles

Irrwahn said:
N869
7.19.2 Streams
[#2] A text stream is an ordered sequence of characters
composed into lines, each line consisting of zero or more
characters plus a terminating new-line character. Whether
the last line requires a terminating new-line character is
implementation-defined.

That makes the requirement for a final '\n' in the stream
implementation specific. It in no way implies that fgets has any
flexibility on how it process the final line. fgets is required to

read at most n-1 bytes
stop after reading and retaining an '/n' or after reaching eof
return the array address in all cases except
eof encountered without transferring any data
a read error occurs

Nowhere in the standard is any implementation-defined or undefined
behavior specifically described for fgets. This includes the case
where the stream does not terminate with a '\n', whether required to
or not.


Goodness, what a relief! I was already worrying about having to rewrite
all the code that makes use of fgets().

<SNIP>

Irrwahn
Hi All
There is another problem with feof() when used with functions like
fscanf(). In code like below, you will not get an EOF and spin forever!

while( ! feof(infile)) {
fscanf( infile," %d", &in );
}
If the format "%d" fails, fscanf will NOT move forward and this code
will hang. I just ran into this problem with working code and a
corrupted file. fscanf returns the number of data converted, so what
that for a NULL or less that you expected.

Hope this helps
Cliff
mailto: (e-mail address removed)
Clifton R. Liles "Software to the Stars" (e-mail address removed)
Pearland, TX 77581 (e-mail address removed) (e-mail address removed)
- Speaking for myself! Standard disclaimer applies. -
This address may *not* be used for unsolicited mailings.
Failure is not an option. It comes bundled with your Microsoft product.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top