fgets not doing as I expect

S

sandeep

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;
}
 
E

Eric Sosman

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.
 
S

sandeep

Eric said:
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.
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.
 
S

sandeep

Richard said:
sandeep wrote:

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)++;
}
 
E

Eric Sosman

Eric said:
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;
}
[...]

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) */
}
 
K

Keith Thompson

sandeep said:
Eric said:
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.
 
M

Malcolm McLean

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.
 
N

Nick Keighley

On Jun 2, 10:08 pm, sandeep <[email protected]> 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);
 
B

Ben Bacarisse

Nick Keighley said:
On 3 June, 06:58, Malcolm McLean <[email protected]>
wrote:
[...] 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.

--
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.
 
N

Nick Keighley

Ben said:
--
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
 

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

Similar Threads

fgets not doing as I expect. 8
fgets 1
A process take input from /proc/<pid>/fd/0, but won't process it 0
understanding fgets() 11
fgets problem 23
fgets 6
Replacing fgets 32
HELP:function at c returning (null) 3

Members online

Forum statistics

Threads
473,756
Messages
2,569,540
Members
45,025
Latest member
KetoRushACVFitness

Latest Threads

Top