Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > fgets not doing as I expect

Reply
Thread Tools

fgets not doing as I expect

 
 
sandeep
Guest
Posts: n/a
 
      06-02-2010
I wanted to limit how many chars I read in, but the code below instead of
stopping at
7 chars will happily read 30 or 40 car lines and spit them out. Not what
I expected.

#include<stdio.h>
main(){
char line [4096];

while (NULL!=fgets(line,8,stdin))
{
printf("%s",line);
}

return 0;
}
 
Reply With Quote
 
 
 
 
Eric Sosman
Guest
Posts: n/a
 
      06-02-2010
On 6/2/2010 2:29 PM, sandeep wrote:
> I wanted to limit how many chars I read in, but the code below instead of
> stopping at
> 7 chars will happily read 30 or 40 car lines and spit them out. Not what
> I expected.
>
> #include<stdio.h>
> main(){
> char line [4096];
>
> while (NULL!=fgets(line,8,stdin))
> {
> printf("%s",line);
> }
>
> return 0;
> }


Your code reads the first seven characters, prints them,
goes back and reads the next seven, prints them, goes back and
reads the next seven, ... The fgets() function will stop for
three reasons: (1) it reads and stores a '\n', (2) it fills
the buffer, or (3) there's no more input to read (end-of-input
or I/O error). In cases (1) and (2), the next fgets() will
resume where the first one left off -- for example, with the
eighth character of a 30-character line.

--
Eric Sosman
http://www.velocityreviews.com/forums/(E-Mail Removed)lid
 
Reply With Quote
 
 
 
 
sandeep
Guest
Posts: n/a
 
      06-02-2010
Eric Sosman writes:
> On 6/2/2010 2:29 PM, sandeep wrote:
>> I wanted to limit how many chars I read in, but the code below instead
>> of stopping at
>> 7 chars will happily read 30 or 40 car lines and spit them out. Not
>> what I expected.
>>
>> #include<stdio.h>
>> main(){
>> char line [4096];
>>
>> while (NULL!=fgets(line,8,stdin))
>> {
>> printf("%s",line);
>> }
>>
>> return 0;
>> }

>
> Your code reads the first seven characters, prints them,
> goes back and reads the next seven, prints them, goes back and reads the
> next seven, ... The fgets() function will stop for three reasons: (1)
> it reads and stores a '\n', (2) it fills the buffer, or (3) there's no
> more input to read (end-of-input or I/O error). In cases (1) and (2),
> the next fgets() will resume where the first one left off -- for
> example, with the eighth character of a 30-character line.
>
> --
> Eric Sosman
> (E-Mail Removed)lid


I expected that if I typed 123456789 I would get 1234567 out.
I threw in a \n in the printf and it now makes some sense.

Still not behaving how I hoped having the 89 spill over is not what I
wanted, just wanted a nice safe way of inputing size limited fields.
 
Reply With Quote
 
sandeep
Guest
Posts: n/a
 
      06-02-2010
Richard Heathfield writes:

> sandeep wrote:
>
> <snip>
>
>> I expected that if I typed 123456789 I would get 1234567 out. I threw
>> in a \n in the printf and it now makes some sense.
>>
>> Still not behaving how I hoped having the 89 spill over is not what I
>> wanted, just wanted a nice safe way of inputing size limited fields.

>
> You can do that easily enough if you want:
>
> char line[1024] = "";
> char safe[8] = "";
>
> while(fgets(line, 8, stdin) != NULL)
> {
> printf("%s\n", line);
>
> strcpy(safe, line); /* if required for further processing */
>
> /* discard rest of overly long lines */ while(strchr(line, '\n') !=
> NULL &&
> fgets(line, sizeof line, stdin) != NULL)
> {
> continue;
> }
> }
> --
> Richard Heathfield <http://www.cpax.org.uk>
> Email: -http://www. +rjh@
> "Usenet is a strange place" - dmr 29 July 1999
> Sig line vacant - apply within


I am writing some code that needs user input to fill in some structure
fields in an
array and I wanted to make sure that it was done safely.

The scanf below for qty seems to leave a \n that clobbers location. Been
a while
since I have done serious coding, I don't remember this many problems
before

void addpart(PART p[],int *n){

printf("Adding a part.\n"
"Please enter a part number:");
fgets(p[*n].part,sizeof(p[0].part),stdin);
printf("Please enter part description:");
fgets(p[*n].description,sizeof(p[0].description),stdin);
printf("Please enter quantity:");
scanf("%hu",&p[*n].qty);
printf("Please enter location:");
fgets(p[*n].location,5,stdin);
(*n)++;
}
 
Reply With Quote
 
Eric Sosman
Guest
Posts: n/a
 
      06-02-2010
On 6/2/2010 3:08 PM, sandeep wrote:
> Eric Sosman writes:
>> On 6/2/2010 2:29 PM, sandeep wrote:
>>> I wanted to limit how many chars I read in, but the code below instead
>>> of stopping at
>>> 7 chars will happily read 30 or 40 car lines and spit them out. Not
>>> what I expected.
>>>
>>> #include<stdio.h>
>>> main(){
>>> char line [4096];
>>>
>>> while (NULL!=fgets(line,8,stdin))
>>> {
>>> printf("%s",line);
>>> }
>>>
>>> return 0;
>>> }

>> [...]
>> --
>> Eric Sosman
>> (E-Mail Removed)lid


Please don't quote signatures.

> I expected that if I typed 123456789 I would get 1234567 out.
> I threw in a \n in the printf and it now makes some sense.
>
> Still not behaving how I hoped having the 89 spill over is not what I
> wanted, just wanted a nice safe way of inputing size limited fields.


You need to determine whether fgets() read an entire line,
or just the beginning of a line with the tail still waiting to
be read. The determination is easy, or "almost easy:" if the
buffer contains a newline character, fgets() read an entire line.
Unfortunately, the opposite is not necessarily true (this is the
"almost" part): If the buffer has no newline, either fgets()
filled the buffer and stopped with the tail of the line unread,
or fgets() encountered end-of-input without seeing a newline (on
some systems this can't happen; on others it can).

If all you want to do is discard the unread tail of any too-
long line, that's easy: When fgets() gives you no newline, just
read and discard characters until you get a newline or EOF:

while (NULL != fgets(line, 8, stdin)) {
if (strchr(line, '\n') == NULL) {
/* no newline; skip a possible tail */
int ch;
while ( (ch = getchar()) != '\n' ) {
if (ch == EOF) {
if (ferror(stdin))
/* respond to I/O error */ ;
break;
}
}
}
/* do what you will with the line (or line prefix) */
}

--
Eric Sosman
(E-Mail Removed)lid
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      06-02-2010
sandeep <(E-Mail Removed)> writes:
> Eric Sosman writes:
>> On 6/2/2010 2:29 PM, sandeep wrote:
>>> I wanted to limit how many chars I read in, but the code below instead
>>> of stopping at
>>> 7 chars will happily read 30 or 40 car lines and spit them out. Not
>>> what I expected.
>>>
>>> #include<stdio.h>
>>> main(){
>>> char line [4096];
>>>
>>> while (NULL!=fgets(line,8,stdin))
>>> {
>>> printf("%s",line);
>>> }
>>>
>>> return 0;
>>> }

>>
>> Your code reads the first seven characters, prints them,
>> goes back and reads the next seven, prints them, goes back and reads the
>> next seven, ... The fgets() function will stop for three reasons: (1)
>> it reads and stores a '\n', (2) it fills the buffer, or (3) there's no
>> more input to read (end-of-input or I/O error). In cases (1) and (2),
>> the next fgets() will resume where the first one left off -- for
>> example, with the eighth character of a 30-character line.

>
> I expected that if I typed 123456789 I would get 1234567 out.


That's exactly what you got.

You also got the "89", immediately following the "1234567".

> I threw in a \n in the printf and it now makes some sense.
>
> Still not behaving how I hoped having the 89 spill over is not what I
> wanted, just wanted a nice safe way of inputing size limited fields.


What do you mean by "safe"? You can't stop the user from entering
a long input line. You need to decide how to respond if the user
does this. One option is to print an error message. Another is
to silently discard the extra input -- but you still have to read
it to be able to discard it.

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
Malcolm McLean
Guest
Posts: n/a
 
      06-03-2010
On Jun 2, 10:08*pm, sandeep <(E-Mail Removed)> wrote:
> just wanted a nice safe way of inputing size limited fields.- Hide quoted text -
>

There's no easy weay of doing this, because there is no obvious
threshold you canuse for sanity testing.

Humans are unlikely to type more than a few hundred characters at the
prompt, but free text paragraphs can be very long, and automatically
generated data can be even longer. fgets() is too difficult to use
correctly if lines may overflow, because you have to check the
newline, then do something with the half-read buffer, then recover
from the error. It's almost as easy to roll your own function.


 
Reply With Quote
 
Nick Keighley
Guest
Posts: n/a
 
      06-03-2010
On 3 June, 06:58, Malcolm McLean <(E-Mail Removed)>
wrote:
> On Jun 2, 10:08*pm, sandeep <(E-Mail Removed)> wrote:


> *just wanted a nice safe way of inputing size limited fields.- Hide quoted text -
>
> There's no easy weay of doing this, because there is no obvious
> threshold you canuse for sanity testing.


use fgets() to read the characters you want, then call fgetc() or
fgets() and discard the result until you reach the end of the line.


> Humans are unlikely to type more than a few hundred characters at the
> prompt, but free text paragraphs can be very long, and automatically
> generated data can be even longer. fgets() is too difficult to use
> correctly if lines may overflow, because you have to check the
> newline, then do something with the half-read buffer, then recover
> from the error.


nonsense. fgets() is perfectly straightforward.


> It's almost as easy to roll your own function.


seems a lot of work when the functionality is already provided. Which
stdio function do you use to implement your roll-your-own?


--
The fscanf equivalent of fgets is so simple
that it can be used inline whenever needed:-
char s[NN + 1] = "", c;
int rc = fscanf(fp, "%NN[^\n]%1[\n]", s, &c);
if (rc == 1) fscanf("%*[^\n]%*c);
if (rc == 0) getc(fp);

 
Reply With Quote
 
Ben Bacarisse
Guest
Posts: n/a
 
      06-03-2010
Nick Keighley <(E-Mail Removed)> writes:

> On 3 June, 06:58, Malcolm McLean <(E-Mail Removed)>
> wrote:

<snip>
>> [...] fgets() is too difficult to use
>> correctly if lines may overflow, because you have to check the
>> newline, then do something with the half-read buffer, then recover
>> from the error.

>
> nonsense. fgets() is perfectly straightforward.


I don't agree with Malcolm McLean but I stop some way short of
"perfectly straightforward". It seems less than straightforward to have
to scan the array to see if a whole line was read, and the methods that
avoid this scan are fiddly to get right.

<snip>
> --
> The fscanf equivalent of fgets is so simple
> that it can be used inline whenever needed:-
> char s[NN + 1] = "", c;
> int rc = fscanf(fp, "%NN[^\n]%1[\n]", s, &c);
> if (rc == 1) fscanf("%*[^\n]%*c);
> if (rc == 0) getc(fp);


This is in your sig so you are presumably quoting it for the purposes of
mockery. The ways in which it falls short of duplicating fgets are
sufficiently numerous that humour can be the only motivation for
including it.

--
Ben.
 
Reply With Quote
 
Nick Keighley
Guest
Posts: n/a
 
      06-03-2010
On 3 June, 12:31, Richard Heathfield <(E-Mail Removed)> wrote:
> Ben Bacarisse wrote:
> > Nick Keighley <(E-Mail Removed)> writes:


> >> --
> >> The fscanf equivalent of fgets is so simple
> >> that it can be used inline whenever needed:-
> >> * * char s[NN + 1] = "", c;
> >> * * int rc = fscanf(fp, "%NN[^\n]%1[\n]", s, &c);
> >> * * if (rc == 1) fscanf("%*[^\n]%*c);
> >> * * if (rc == 0) getc(fp);

>
> > This is in your sig so you are presumably quoting it for the purposes of
> > mockery. *The ways in which it falls short of duplicating fgets are
> > sufficiently numerous that humour can be the only motivation for
> > including it.

>
> Um, for one thing it ain't gonna compile.


I was aware of at least one error in it, but I felt that kind of
illustrated the point


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
boost bind expression not doing what I expect Stone Free C++ 5 08-20-2009 05:13 PM
fgets not doing as I expect. Ben Bacarisse C Programming 8 12-27-2008 08:53 AM
how to expect eof with expect+pty Simon Strandgaard Ruby 4 12-20-2006 04:00 PM
Asynchronous call question- app isn't doing what I expect. RobGSCL ASP .Net Web Services 3 10-30-2006 03:57 PM
Bug in $obj->expect() ... ? (Expect 1.15) Phil Perl Misc 0 07-07-2006 07:25 AM



Advertisments