newbie question: fgets() and feof() read last line twice

A

Andy

I read the C.FAQ

http://c-faq.com/stdio/feof.html

I know it is not a good practice to use feof(). My question is: if I
have the following code,

--------------------------------------------------------<code>
#include <stdio.h>
#include <stdlib.h>

int main(){
FILE *fp;
char line[50];
char *p;

fp = fopen("tmp", "r"); /* fp == NULL check is ignored */

printf("fpos=%d\n", ftell(fp));

while(!feof(fp)){
p = fgets(line, sizeof line, fp);
printf("p=%p, %s", p, line);
printf("fpos=%d\n", ftell(fp));
}
fclose(fp);

exit(0);
}
--------------------------------------------------------<code>

--------------------------------------------------------<tmp>
line1\n
line2\n
line3\n
--------------------------------------------------------<tmp>

why the last line twice?

After opening the file, fpos = ftell(fp) is 0, then fgets() reads
"line1", so fpos=6.

fgets() reads "line2"
fpos = 12

fgets() reads "line3"
fpos = 18

right now, fp is pointing at the end of the file, while is a place
after "line3\n". The next time fgets() trys to read again, it will
signal the end-of-file, and also the line is SUPPOSED to be set to
'\0', so it should NOT print the previous store line value again.....

Here is an implementation of K&R2 on p.165 of fgets()

--------------------------------------------------------<code>
char *fgets(char *s, int n, FILE *iop){
register int c;
register char *cs;

cs = s;
while(--n >0 && (c=getc(iop)) != EOF)
if((*cs++ = c) == '\n') break;

*cs = '\0';
return (c==EOF && cs == s)? NULL : s;
}
--------------------------------------------------------<code>

If I use this function, then the last line will not appear TWICE... I
am thinking how the stdlib really implements this function...

BTW, fscanf() will signal the END_OF_FILE IMMEDIATELY after its
read????

Thanks for any advice!

~Andy W.
 
B

Ben Bacarisse

Andy said:
I read the C.FAQ

http://c-faq.com/stdio/feof.html

I know it is not a good practice to use feof(). My question is: if I
have the following code,

--------------------------------------------------------<code>
#include <stdio.h>
#include <stdlib.h>

int main(){
FILE *fp;
char line[50];
char *p;

fp = fopen("tmp", "r"); /* fp == NULL check is ignored */

printf("fpos=%d\n", ftell(fp));

while(!feof(fp)){
p = fgets(line, sizeof line, fp);
printf("p=%p, %s", p, line);
printf("fpos=%d\n", ftell(fp));
}
fclose(fp);

exit(0);
}
--------------------------------------------------------<code>

--------------------------------------------------------<tmp>
line1\n
line2\n
line3\n
--------------------------------------------------------<tmp>

why the last line twice?

Ok. See later.
After opening the file, fpos = ftell(fp) is 0, then fgets() reads
"line1", so fpos=6.

fgets() reads "line2"
fpos = 12

fgets() reads "line3"
fpos = 18

right now, fp is pointing at the end of the file, while is a place
after "line3\n". The next time fgets() trys to read again, it will
signal the end-of-file, and also the line is SUPPOSED to be set to
'\0', so it should NOT print the previous store line value
again.....

This is the heart of it. When fgets sees the end of the stream and no
characters have been read the contents of the buffer must be left
unchanged. This is mandated by the standard.
Here is an implementation of K&R2 on p.165 of fgets()

--------------------------------------------------------<code>
char *fgets(char *s, int n, FILE *iop){
register int c;
register char *cs;

cs = s;
while(--n >0 && (c=getc(iop)) != EOF)
if((*cs++ = c) == '\n') break;

*cs = '\0';
return (c==EOF && cs == s)? NULL : s;
}
--------------------------------------------------------<code>

If I use this function, then the last line will not appear TWICE... I
am thinking how the stdlib really implements this function...

Correctly it would seem! This may be a known error in K&R2 or you may
have found a new one, but the above does not conform to either the old
or new C standard.
BTW, fscanf() will signal the END_OF_FILE IMMEDIATELY after its
read????

By signal END_OF_FILE I take it you mean "causes feof to return true"?
If so then yes it can but not always. It has an embedded language in
the format string and exactly what it returns and how far ahead it is
permitted to read to try to satisfy it requires a very close reading
of the specification.
 
A

Andy

[...]>           printf("fpos=%d\n", ftell(fp));

[...]

I think you meant:

          printf("fpos=%ld\n", ftell(fp));

Yes, you are right. I should use "%ld"... "%d" is wrong. But I am
luck, little-endian...
 

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

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,023
Latest member
websitedesig25

Latest Threads

Top