Check out feof and ferror.
-LZ
My question is, what does it return if characters are read from a file and
EOF is encountered during the read? NULL is only returned on a read error or
if no characters are read, otherwise it returns the pointer. This leads me
to believe it would read the characters until EOF and stop and on the next
call would encounter EOF and return NULL. However, I need to distinguish
between these two cases because if a read error occurs, I need to free a
buffer I've created but I don't need to free it if it has read in characters
followed by EOF. I'm trying the function feof after each call but it isn't
helping any. Here's the function I'm I'm trying to write, I don't have to say
it because I know you will but feel free to criticize my code.
char *Read_Line_Cmn( FILE *fpFile )
{
char *line = NULL, *temp = NULL;
int buff_size = 0, index = 0;
/* Calc new buffer size and malloc */
buff_size += MALLOC_STEP;
line = malloc( buff_size );
if( line == NULL ){ return NULL; }
/* Loop and read the line until EOF or '\n' is encountered. */
/* Reallocate memory as necessary to hold entire line. */
while( TRUE )
{
temp = line;
line = fgets( &line[index], MALLOC_STEP, fpFile );
if( feof( fpFile )){ printf("common.c: EOF\n");line = temp; break; }
if( line == NULL ){ free( holder ); return NULL; }
line = temp;
if( (temp = strchr( line, '\n' ))){ temp[0] = 0; break; }
buff_size += MALLOC_STEP;
line = realloc( line, buff_size );
index = strlen( line );
}
return line;
}
Thanks in advance,
Robert
Whoops, I didn't quite read the whole thing. Okay fread will return to you
an integer count of characters upto the EOF. At this point, C would set it's
internal eof flag. The next time you call it, you'll get a zero back because
of the eof. If you check feof before every fread, you should never get back
a zero from fread unless there is a real live read error. If you don't want
to check feof before every read, then once you get an zero back, check feof.
If a read error occured before the eof, that flag won't be set. Or you could
check ferror.
-LZ
Robert
Lou Zher (ab...@localhost.com) wrote:
: Robert Jon Bredlau <rbre...@cats.ucsc.edu> wrote in message
:
:
Man, I suck. I mis-read that whole message like twelve different ways. Well,
the same thing applies for fgets. If, in the middle of a line, you have a
^Z, fgets puts the good stuff in your buf and says all's good, but also sets
the eof flag. If you check feof at this point, it will return true. fgets
will fail if you call it again.
char buffer[256], *ptr=buffer;
while (!feof(stream))
{
ptr = fgets(buffer, sizeof(buffer), stream)
if (ptr==NULL)
{
printf("Read error");
break;
}
puts(buffer); // display line
}
if (ptr!=NULL)
printf("EOF");
another call to fgets here will return a NULL.
if your file looks like this:
line 1 blah, blah, blah
line 2 blah, bl^z
the first fgets gives you "line 1 blah, blah, blah"
the second fgets gives you "line 2 blah, bl"
a check of feof, returns true at this point
the third fgets gives you NULL.
Wow... sorry about the confusion before.
-LZ
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define STEP 2
char *Read_Line_Cmn(FILE *fpFile)
{
char *temp, *line = NULL;
int size = 1;
while (1) {
size += STEP - 1;;
if (!(temp = realloc(line, size))) {
/* error, out of memory */
if (line) {
free(line); /* free if memory was allocated */
}
line = NULL; /* return value on error */
break;
}
line = temp;
if (!(fgets(line + size - STEP, STEP, fpFile))) {
/* no input read to buffer */
if (feof(fpFile)) {
/* end of file encountered */
break;
}
if (ferror(fpFile)) {
/* error encountered, discard current input */
free(line); /* free allocated memory */
line = NULL; /* return value on error */
break;
}
}
if ((temp = strchr(line, '\n'))) {
/* end of line encountered */
*temp = '\0'; /* delete newline */
break;
}
}
/* returns NULL on error, or ptr to string in a malloc'ed buffer */
return line;
}
--
Floyd L. Davidson fl...@barrow.com
Ukpeagvik (Barrow, Alaska)
#define MALLOC_STEP 10
/******************************************************************************
** Function : Read_Line_Cmn
** Usage : charptr = Read_Line_Cmn( file );
** file : File stream to read line from
** Read a line of arbitrary length from file not including the '\n'
** and return the pointer to the client. Note that the client
** should free( charptr ) on this pointer. NULL is returned on any
** error, otherwise a pointer to the newly allocated buffer
** containing the line. Note the client should free this buffer.
******************************************************************************/
char *Read_Line_Cmn( FILE *fpFile )
{
char *line = NULL, *temp = NULL;
int buff_size = 0, index = 0;
/* Calc new buffer size and malloc */
buff_size += MALLOC_STEP;
line = malloc( buff_size );
if( line == NULL ){ return NULL; }
/* Loop and read the line until EOF or '\n' is encountered. */
/* Reallocate memory as necessary to hold entire line. */
while( !feof( fpFile ))
{
temp = line;
line = fgets( &line[index], MALLOC_STEP, fpFile );
if( line == NULL ){ free( line ); line = NULL; break; }
line = temp;
if( (temp = strchr( line, '\n' ))){ temp[0] = 0; break; }
buff_size += MALLOC_STEP;
if( !(temp = realloc( line, buff_size )))
{ free( line ); line = NULL; break; }
line = temp;
index = strlen( line );
}
return line;
}
Once again, thanks for the help folks. 8)
Robert
Floyd Davidson (fl...@ptialaska.net) wrote:
:
I stole this chunk of code. Thanks!
: if (!(temp = realloc(line, size))) {
You're closer, but not quite there yet.
>#define MALLOC_STEP 10
>
>/******************************************************************************
>** Function : Read_Line_Cmn
>** Usage : charptr = Read_Line_Cmn( file );
>** file : File stream to read line from
>** Read a line of arbitrary length from file not including the '\n'
>** and return the pointer to the client. Note that the client
>** should free( charptr ) on this pointer. NULL is returned on any
>** error, otherwise a pointer to the newly allocated buffer
>** containing the line. Note the client should free this buffer.
>******************************************************************************/
>char *Read_Line_Cmn( FILE *fpFile )
>{
> char *line = NULL, *temp = NULL;
> int buff_size = 0, index = 0;
>
> /* Calc new buffer size and malloc */
> buff_size += MALLOC_STEP;
> line = malloc( buff_size );
> if( line == NULL ){ return NULL; }
> /* Loop and read the line until EOF or '\n' is encountered. */
> /* Reallocate memory as necessary to hold entire line. */
> while( !feof( fpFile ))
This can just as well be while (1), because feof() will never
return non-zero.
> {
> temp = line;
> line = fgets( &line[index], MALLOC_STEP, fpFile );
> if( line == NULL ){ free( line ); line = NULL; break; }
If fgets() returns NULL because of an end of file condition, you
are throwing away everything which has been previously read into
the buffer, just the same as if it were NULL because of a read
error. The test for feof() needs to be done here, not as the
loop condition. (As written, your code will work if and only if
the last character to be read in is a newline.)
> line = temp;
> if( (temp = strchr( line, '\n' ))){ temp[0] = 0; break; }
> buff_size += MALLOC_STEP;
> if( !(temp = realloc( line, buff_size )))
> { free( line ); line = NULL; break; }
> line = temp;
> index = strlen( line );
There is no real need for strlen() to determine how long the
string is. The only reason execution is still inside the while
loop is because no read error, end of file, or newline as been
encountered, which means the buffer was filled and the last
element of the buffer has been set to 0. That means you can
allocate MALLOC_STEP more space, and perform another fgets()
starting at (line + buff_size - MALLOC_STEP - 1).
In the example I provided earlier the only tricky part of using
the above offset to calculate the start point is to be sure to
initialize the size to 1 so that on the first pass it is
decremented to a 0 offset.
Note also that your code requires calling malloc() initially,
and the example does not. Otherwise, aside from other
formatting style issues, you might find that the construct
"&line[index]" would really be better expressed as a pointer
plus various offsets.
Floyd
"Lou Zher" <ab...@localhost.com> wrote:
>Robert Jon Bredlau <rbre...@cats.ucsc.edu> wrote:
>>How's this:
>> temp = line;
>> line = fgets( &line[index], MALLOC_STEP, fpFile );
>> if( line == NULL ){ free( temp ); break; }
>> line = temp;
>
>For clarity, you might want to consider changing it to this:
>temp = fgets( &line[index], MALLOC_STEP, fpFile )
>if (temp == NULL) {
> free( line );
> line = NULL;
> break;
>}
>
>or just...
>
>if (fgets( &line[index], MALLOC_STEP, fpFile ) == NULL) {
> free( line );
> line = NULL;
> break;
>}
>
>The var that receives from alloc should never be modified until
>after free, and then only to set it to NULL.
As long as the value of the pointer is saved in another
variable, and it is that value which is given to free(), it
makes no difference if the variable is changed or not. The
original poster did not do that, and was trying to free a null
pointer, but that made little difference since the entire
snippet of code was incorrect anyway.
>Well, I finally got it to work. Here's the finished function if anyone wants
>to use it. I'm not sure how fool proof it is but it did read in a line with
>over 40,000 characters.
<snip>
> line = fgets( &line[index], MALLOC_STEP, fpFile );
> if( line == NULL ){ free( line ); line = NULL; break; }
This isn't going to work. If line is NULL you lost the pointer, ie you
have leaked memory. Then you free the NULL pointer (safe but
pointless) then you set a NULL pointer to NULL. Also safe but
pointless...
Mark McIntyre
I love you guys!
8)
:
:
: Mark McIntyre
:
: C- FAQ: http://www.eskimo.com/~scs/C-faq/top.html
For clarity, you might want to consider changing it to this:
temp = fgets( &line[index], MALLOC_STEP, fpFile )
if (temp == NULL) {
free( line );
line = NULL;
break;
}
or just...
if (fgets( &line[index], MALLOC_STEP, fpFile ) == NULL) {
free( line );
line = NULL;
break;
}
The var that receives from alloc should never be modified until after free,
and then only to set it to NULL.
-LZ
The snippnet sits in a feof checking loop. The free & break are only
occuring on error.
From: rbre...@cats.ucsc.edu (Robert Jon Bredlau)
Message-ID: <8cod0k$j...@darkstar.ucsc.edu>
>while( !feof( fpFile ))
> {
> temp = line;
> line = fgets( &line[index], MALLOC_STEP, fpFile );
> if( line == NULL ){ free( line ); line = NULL; break; }
> line = temp;
Floyd Davidson <fl...@ptialaska.net> wrote in message
news:87purzn...@barrow.com...
>"Lou Zher" <ab...@localhost.com> wrote:
>>For clarity, you might want to consider changing it to this:
[snip]
>>
>>The var that receives from alloc should never be modified until
>>after free, and then only to set it to NULL.
>
> As long as the value of the pointer is saved in another
> variable, and it is that value which is given to free(), it
> makes no difference if the variable is changed or not. The
> original poster did not do that, and was trying to free a null
> pointer, but that made little difference since the entire
> snippet of code was incorrect anyway.
Perhaps the superlative /never/ in my statement was a bit harsh. It would be
like playing musical chairs with the file handles/streams. I just consider
it bad form. You open it? you close it. You alloc it? you free it. To the
compiler it makes no difference. In run-time it makes no difference. At
debug time, it might.
-LZ
If previous calls to fgets() have read in some multiple of
MALLOC_STEP bytes which are exactly the last bytes in a file
which ends without a newline,
1) the test for feof() as the while-loop condition will be false,
2) the fgets() call will
a) find no input data to read
b) but will attempt to read past the end of the file,
c) and therefore will return NULL,
3) and therefore all buffered data will be discarded.
The appropriate place to test for feof() is immediately after a call
to fgets() which has returned a NULL, and based on feof() the existing
buffer should be discarded or not.
Floyd
Whoops... you're correct. It's actually worse than that though. Files ending
in newline, then EOF cause feof to miss it, but fgets to fail from eof.
Your fix works.
-LZ
That is why in my original article pointed out that the
conditional for the while-loop using feof() would never indicate
an eof condition and should be replaced with a "while (1) {...}"
loop.
Floyd
>Your fix works.