char* buf[100];
char* p;
fgets(buf, sizeof buf, stdin);
if ((p = strchr(buf, '\n')) != NULL)
{
*p = '\0';
puts("No overflow occurred);
}
else
puts("Overflow occurred");
thanks
clark
It can't overflow in the sense of writing beyond the end of the buffer.
If there is no newline, the line was too long for the buffer, and the
unread portion of the line is still out there to be read with the next
fgets.
> It can't overflow in the sense of writing beyond the end of the buffer.
>
> If there is no newline, the line was too long for the buffer, and the
> unread portion of the line is still out there to be read with the next
> fgets.
(Or the last "line" has no new-line, and the next call to fgets() will
return NULL.)
yes, sadly, that's the only way to do it. it would be very worth your while
to make your own get_line() function which will continuously fgets(),
perhaps like:
#define INITIAL_BUFFER_SIZE 64
char *
get_line(FILE *f)
{
size_t l = INITIAL_BUFFER_SIZE / 2;
char *r = calloc(INITIAL_BUFFER_SIZE / 2, 1);
if (! r) you_re_really_in_trouble;
while (1) {
char lne[l];
size_t lne_len;
if (! fgets(l, sizeof l, f))
unexpected_EOF;
lne_len = strlen(l);
if (l[lne_len - 1] == '\n')
l[lne_len - 1] = 0;
else
break;
r = realloc(r, (l *= 2) * sizeof *r);
if (! r) out_of_memory;
strcpy(r, l);
}
return r;
}
it relies on (commonly used) C99 behaviour. it's probably slow. it's
definitely ugly. it's just to give you an idea of what you could do.
the point is, though, as you've found out, using fgets() just by itself is
very ugly. you have to check for the existance of a newline and then make
some decisions on what to do if there is an overflow, so i find this kind of
function very useful for reading in strings.
--
/"\ m i k e b u r r e l l
\ / ASCII RIBBON CAMPAIGN mik...@home.com
X AGAINST HTML MAIL,
/ \ AND NEWS TOO, dammit finger mik...@mikpos.dyndns.org for GPG key
You don't have to, because fgets() is guaranteed not to overflow its
buffer (or, rather, it won't write more than the number of bytes you
tell it it can, via the second argument). Of course, what that means is
that it may not be able to collect a whole line of data in one go.
> i do
> check to see if there is a trailing newline, might that be on the right
> track? i.e. if there is no newline, then overflow occurred?
Close. If there's no newline, it means that there was more data than
would fit in the buffer, and so buffer overflow /would have/ occurred,
if you'd been using gets()!
What does fgets() do with that extra data? Nothing. It leaves it alone.
You can collect it, therefore, using another call to fgets(). This is
rather useful. Those people who say "fgets() is irritating because it
doesn't get rid of the '\n' character" haven't thought enough about just
how important it is that fgets() should /not/ do this.
--
Richard Heathfield
"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
65 K&R Answers: http://users.powernet.co.uk/eton/kandr2/index.html (32
to go)
that's what i meant, of course. oops. not overflow in the sense that the
data would be written past the end of the buffer, but that the buffer would
be filled with data, and "overflow" would occur if there was data left on
stdin to be read.
Richard Heathfield wrote:
> Andrew Clark wrote:
> >
> > people are always saying that gets() and scanf() are evil, so i now use
> > fgets() exclusively. but i don't know how to check for buffer overflow.
>
> You don't have to, because fgets() is guaranteed not to overflow its
> buffer (or, rather, it won't write more than the number of bytes you
> tell it it can, via the second argument). Of course, what that means is
> that it may not be able to collect a whole line of data in one go.
>
> > i do
> > check to see if there is a trailing newline, might that be on the right
> > track? i.e. if there is no newline, then overflow occurred?
>
> Close. If there's no newline, it means that there was more data than
> would fit in the buffer, and so buffer overflow /would have/ occurred,
> if you'd been using gets()!
>
> What does fgets() do with that extra data? Nothing. It leaves it alone.
> You can collect it, therefore, using another call to fgets(). This is
> rather useful. Those people who say "fgets() is irritating because it
> doesn't get rid of the '\n' character" haven't thought enough about just
> how important it is that fgets() should /not/ do this.
What is it useful for ?
It's useful for those situations where you are prepared to deal with
strings in bulk, but don't know in advance how long those strings will
be. Thus, consider a simple tee:
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *fp = NULL;
char buffer[80];
/* insert argc/argv checking code here */
fp = fopen(argv[1], "w");
if(fp != NULL)
{
while(fgets(buffer, sizeof buffer, stdin))
{
printf("%s", buffer); /* one of those times we don't want \n */
fprintf(fp, "%s, buffer); /* another of those times */
}
fflush(stdout);
fflush(fp);
fclose(fp);
}
else
{
fprintf(stderr, "Broken tee.\n");
}
return 0;
}
That was pretty trivial. Note the complete absence of newline handling.
Very elegant.
A more complex example might involve reading an entire text file into
memory. Here, it's useful to be able to read the file into memory in
one-line chunks, but we don't know in advance how long a line is, but
that's okay, because fgets() "paginates" the line for us in
easy-to-handle sections, which we can string together using realloc.
I won't show code here, but I've published that exact example recently
(hmm - does that count as a plug? If so, my apologies); Malc- 'gets()'
-olm might be interested to know that it is the very example of robust
fgets() that I wouldn't show him a few months back.
>
>
>Richard Heathfield wrote:
>
>> Andrew Clark wrote:
>> >
>> > people are always saying that gets() and scanf() are evil, so i now use
>> > fgets() exclusively. but i don't know how to check for buffer overflow.
>>
>> You don't have to, because fgets() is guaranteed not to overflow its
>> buffer (or, rather, it won't write more than the number of bytes you
>> tell it it can, via the second argument). Of course, what that means is
>> that it may not be able to collect a whole line of data in one go.
>>
>> > i do
>> > check to see if there is a trailing newline, might that be on the right
>> > track? i.e. if there is no newline, then overflow occurred?
>>
>> Close. If there's no newline, it means that there was more data than
>> would fit in the buffer, and so buffer overflow /would have/ occurred,
>> if you'd been using gets()!
>>
>> What does fgets() do with that extra data? Nothing. It leaves it alone.
>> You can collect it, therefore, using another call to fgets(). This is
>> rather useful. Those people who say "fgets() is irritating because it
>> doesn't get rid of the '\n' character" haven't thought enough about just
>> how important it is that fgets() should /not/ do this.
>
>What is it useful for ?
(I assume you mean fgets()'s behaviour regarding the newline.)
Let's say we want to read some lines from a text file, and write them
somewhere else, while maintaining the original structure of the lines.
#include <stdio.h>
void foo(FILE *in, FILE *out)
{
char buffer[50];
while (fgets(buffer, sizeof buffer, in) != NULL) {
fputs(buffer, out);
}
}
Let's also say that there are some lines in the text file that are longer
that are longer that 49 characters. The call to fgets() will read the
first part, then it's written to the output stream. The next call to
fgets() will read the second part. Eventually it'll hit a newline, and the
newline will be printed with the buffer.
If fgets() discarded the newline, we'd never know whether an entire line
had been read, or just part of a line.
q = realloc(r, (l *= 2) * sizeof *r);
if(NULL == q)
{
/* error stuff here */
}
else
{
r = q;
}
> if (! r) out_of_memory;
>
> strcpy(r, l);
> }
>
> return r;
>}
>
>it relies on (commonly used) C99 behaviour. it's probably slow. it's
>definitely ugly. it's just to give you an idea of what you could do.
>
>the point is, though, as you've found out, using fgets() just by itself is
>very ugly. you have to check for the existance of a newline and then make
>some decisions on what to do if there is an overflow, so i find this kind of
>function very useful for reading in strings.
>
--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Bob Wightman
<snip>
mike> char * get_line(FILE *f) { size_t l = INITIAL_BUFFER_SIZE /
mike> 2; char *r = calloc(INITIAL_BUFFER_SIZE / 2, 1);
mike> if (! r) you_re_really_in_trouble;
mike> while (1) { char lne[l]; size_t lne_len;
Isn't that l has to be replaced with lne in this loop??.
mike> if (! fgets(l, sizeof l, f)) unexpected_EOF;
mike> lne_len = strlen(l);
mike> if (l[lne_len - 1] == '\n') l[lne_len - 1] =
mike> 0; else break;
mike> r = realloc(r, (l *= 2) * sizeof *r); if (!
mike> r) out_of_memory;
mike> strcpy(r, l); }
mike> return r; }
<snip>
--
Kolla Suresh Babu
*Note*: Don't use my "Reply To:"
Use <kolla at mailcity dot com>
yes. sorry.
> fflush(fp);
> fclose(fp);
This is off the original question, but can one assume that
when one fcloses a stream it is automatically flushed (making
the above redundant), or is it good practice to include
the fflush explicitly?
Allin Cottrell.
fclose not only flushes, but it has a return value which can indicate its
failure to flush the data. However, whether or not fclose() suceeds in
flushing, the stream is disposed of. Therefore if it is desirable to recover
in some way after a write error, such as by clearing the error indicator and
trying the operation again, then the explicit fflush() is a better choice.
--
Any hyperlinks appearing in this article were inserted by the unscrupulous
operators of a Usenet-to-web gateway, without obtaining the proper permission
of the author, who does not endorse any of the linked-to products or services.
> >This is off the original question, but can one assume that
> >when one fcloses a stream it is automatically flushed (making
> >the above redundant), or is it good practice to include
> >the fflush explicitly?
>
> fclose not only flushes, but it has a return value which can indicate its
> failure to flush the data. However, whether or not fclose() suceeds in
> flushing, the stream is disposed of. Therefore if it is desirable to recover
> in some way after a write error, such as by clearing the error indicator and
> trying the operation again, then the explicit fflush() is a better choice.
I think I see. But then would I be right in saying that
fflush(fp);
fclose(fp);
accomplishes nothing that is not accomplished by just
fclose(fp);
?
Allin Cottrell.
Aside from being able to interrogate "fp" in between the two
operations, yes. I say "aside" because in the past I have used
code of the form:
... sequence of write operations on file "fp" ...
fflush(fp);
if (ferror(fp)) {
warn("%s: write error", filename);
status = FAIL;
}
fclose(fp);
to put in a single "something went wrong while writing a file"
test. (Although it more a comp.unix.programmer thing, this also
lets one write:
fflush(fp);
err2 = fsync(fileno(fp));
if (ferror(fp) || err2) warn ...
fclose(fp);
which not only forces data out of stdio, but also down onto the
underlying storage device. Then too, prior to ANSI C, it was not
entirely clear whether all implementations' fclose() functions
returned a valid error value.)
--
In-Real-Life: Chris Torek, Berkeley Software Design Inc
El Cerrito, CA, USA Domain: to...@bsdi.com +1 510 234 3167
http://claw.bsdi.com/torek/ (not always up) I report spam to abuse@.
> I only put the fflush into that little code snippet because, if I
> hadn't, someone would have complained. So in it went and - oh look! -
> someone complained.
>
> Where's that bottle of Glenfiddich got to? Ah...
So it was a "little stream of whisky" that was being flushed?
Allin Cottrell.
I only put the fflush into that little code snippet because, if I
hadn't, someone would have complained. So in it went and - oh look! -
someone complained.
Where's that bottle of Glenfiddich got to? Ah...
Your health, sir.
;-)
> it relies on (commonly used) C99 behaviour. it's probably slow. it's
> definitely ugly. it's just to give you an idea of what you could do.
>
You can avoid the VLA, and the strcat() etc., by doing
realloc() first and then fgets'ing into the "fresh" part of it,
though you may have to do an N-and-a-half loop.
Or you can start out with a nulled pointer and use the feature
that realloc(null,n) does a malloc; this is either clever or devious
(or both?) depending on how you look at it.
--
- David.Thompson 1 now at worldnet.att.net