By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
445,778 Members | 2,015 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 445,778 IT Pros & Developers. It's quick & easy.

scanf/getchar sequence problem

P: n/a
/*
The below code on SGI will wait for you to enter 2 things, but
on Linux it will only wait the first time.

I can make the code work by replacing the scanf with:

char data [5];
fgets (data,5,stdin);
the_number = atoi (data);

But, instead I would like to modify the scanf, "/dev/tty", or
something simple like that.
*/

#include <stdio.h>
int main()
{
int c;
int the_number;
fprintf (stderr,"Enter Number :");
scanf ("%d",&the_number);
fprintf (stderr,"\nEnter a letter :");
c = getchar ();
if ( (c = getchar ()) == EOF )
freopen ("/dev/tty","r",stdin);
else
ungetc (c,stdin);
return (0);
}

Nov 14 '05 #1
Share this Question
Share on Google+
13 Replies


P: n/a


cl********@aol.com wrote:
/*
The below code on SGI will wait for you to enter 2 things, but
on Linux it will only wait the first time.

I can make the code work by replacing the scanf with:

char data [5];
fgets (data,5,stdin);
the_number = atoi (data);

But, instead I would like to modify the scanf, "/dev/tty", or
something simple like that.
*/

#include <stdio.h>
int main()
{
int c;
int the_number;
fprintf (stderr,"Enter Number :");
scanf ("%d",&the_number);
fprintf (stderr,"\nEnter a letter :");
c = getchar ();
if ( (c = getchar ()) == EOF )
freopen ("/dev/tty","r",stdin);
else
ungetc (c,stdin);
return (0);
}


Linux is right; SGI is wrong. The scanf() should consume
any initial white space, an optional sign character, and a
digit string, but should not consume the following '\n' (or
whatever else follows the digits). The subsequent getchar()
should retrieve the '\n' (or whatever).

My advice is to avoid scanf() for interactive input: it
can be tricky to use, and recovery from input errors is
difficult (consider what happens if the user enters "#\n"
at your first prompt). It is usually better to proceed along
the lines of the "cure" you discovered: Read the line with
fgets() and then interpret the characters yourself. It's
better to use strtod() or sscanf() than atoi(), because the
latter has essentially *no* way to diagnose erroneous input.

--
Er*********@sun.com
Nov 14 '05 #2

P: n/a
"Eric Sosman" <er*********@sun.com> wrote in message
news:d3**********@news1brm.Central.Sun.COM
cl********@aol.com wrote:
/*
The below code on SGI will wait for you to enter 2 things, but
on Linux it will only wait the first time.

I can make the code work by replacing the scanf with:

char data [5];
fgets (data,5,stdin);
the_number = atoi (data);

But, instead I would like to modify the scanf, "/dev/tty", or
something simple like that.
*/

#include <stdio.h>
int main()
{
int c;
int the_number;
fprintf (stderr,"Enter Number :");
scanf ("%d",&the_number);
fprintf (stderr,"\nEnter a letter :");
c = getchar ();
if ( (c = getchar ()) == EOF )
freopen ("/dev/tty","r",stdin);
else
ungetc (c,stdin);
return (0);
}


Linux is right; SGI is wrong. The scanf() should consume
any initial white space, an optional sign character, and a
digit string, but should not consume the following '\n' (or
whatever else follows the digits). The subsequent getchar()
should retrieve the '\n' (or whatever).


Yes, but note that there are two getchar() calls in the code, so it should
be possible to enter a char at the console (though the effect will not be
the intended one).

I wonder if the code run on Linux and the code run on SGI were really the
same.
--
John Carson

Nov 14 '05 #3

P: n/a


John Carson wrote:
"Eric Sosman" <er*********@sun.com> wrote

[...] The subsequent getchar()
should retrieve the '\n' (or whatever).


Yes, but note that there are two getchar() calls in the code, so it should
be possible to enter a char at the console (though the effect will not be
the intended one).


Oh, foozle. I'd like to say "That'll teach me not
to speed-read code," but experience suggests it won't ...

--
Er*********@sun.com

Nov 14 '05 #4

P: n/a
In comp.lang.c cl********@aol.com wrote:
/*
The below code on SGI will wait for you to enter 2 things, but
on Linux it will only wait the first time.
[snip] fprintf (stderr,"Enter Number :");
scanf ("%d",&the_number);
fprintf (stderr,"\nEnter a letter :");
c = getchar ();
if ( (c = getchar ()) == EOF )

[snip]

On Linux works as expected, ie. waits or not depending
on what data you feed (at least at an Xterm). Try to
output values of `c' to see what happens (could it be
that Enter generates more than one character?)

--
Stan Tobias
mailx `echo si***@FamOuS.BedBuG.pAlS.INVALID | sed s/[[:upper:]]//g`
Nov 14 '05 #5

P: n/a

Eric Sosman wrote:
cl********@aol.com wrote:
/*
The below code on SGI will wait for you to enter 2 things, but
on Linux it will only wait the first time.

I can make the code work by replacing the scanf with:

char data [5];
fgets (data,5,stdin);
the_number = atoi (data);

But, instead I would like to modify the scanf, "/dev/tty", or
something simple like that.
*/

#include <stdio.h>
int main()
{
int c;
int the_number;
fprintf (stderr,"Enter Number :");
scanf ("%d",&the_number);
fprintf (stderr,"\nEnter a letter :");
c = getchar ();
if ( (c = getchar ()) == EOF )
freopen ("/dev/tty","r",stdin);
else
ungetc (c,stdin);
return (0);
}


Linux is right; SGI is wrong. The scanf() should consume
any initial white space, an optional sign character, and a
digit string, but should not consume the following '\n' (or
whatever else follows the digits). The subsequent getchar()
should retrieve the '\n' (or whatever).


This is solution temporarily OK'ed by boss:

#include <stdio.h>
int main()
{
int c;
int the_number;
char car_ret;

fprintf (stderr,"Enter Number :");

#ifdef __sgi
scanf ("%d",&the_number);
#elif defined (__linux)
scanf ("%d%c",&the_number,&car_ret);
#endif

fprintf (stderr,"\nEnter a letter :");
c = getchar ();
if ( (c = getchar ()) == EOF )
freopen ("/dev/tty","r",stdin);
else
ungetc (c,stdin);
return (0);
}

Nov 14 '05 #6

P: n/a
cl********@aol.com wrote:
[scanf("%d") leaves the newline unconsumed]

This is solution temporarily OK'ed by boss:

#include <stdio.h>
int main()
{
int c;
int the_number;
char car_ret;

fprintf (stderr,"Enter Number :");

#ifdef __sgi
scanf ("%d",&the_number);
#elif defined (__linux)
scanf ("%d%c",&the_number,&car_ret);
#endif


Fragile; a house of cards. If the user enters anything
at all between the final digit and the newline -- a space
character, say -- you'll be right back where you started.
I'll repeat my earlier advice: scanf() is not well suited
for interactive input, and you'd be better off using another
method altogether.

--
Eric Sosman
es*****@acm-dot-org.invalid
Nov 14 '05 #7

P: n/a
Eric Sosman wrote:

cl********@aol.com wrote:
[scanf("%d") leaves the newline unconsumed]

This is solution temporarily OK'ed by boss:

#include <stdio.h>
int main()
{
int c;
int the_number;
char car_ret;

fprintf (stderr,"Enter Number :");

#ifdef __sgi
scanf ("%d",&the_number);
#elif defined (__linux)
scanf ("%d%c",&the_number,&car_ret);
#endif


Fragile; a house of cards. If the user enters anything
at all between the final digit and the newline -- a space
character, say -- you'll be right back where you started.
I'll repeat my earlier advice: scanf() is not well suited
for interactive input, and you'd be better off using another
method altogether.


Is stderr well suited for interactive output?
I always thought that the purpose of the standard error stream
was to output error messages.

--
pete
Nov 14 '05 #8

P: n/a
Eric Sosman wrote:

I'll repeat my earlier advice: scanf() is not well suited
for interactive input, and you'd be better off using another
method altogether.


And it is a very good advice. The OP should follow it.
The substitution of scanf with a fgets() sscanf() pair isn't
much work and saves you from that problem (and others
you have not discovered yet).

char Buffer[ BUFFER_SIZE ]
fgets( Buffer, sizeof( Buffer ), stdin );
sscanf( "... whatever you want

The only problem is the BUFFER_SIZE. It doesn't matter which number
you choose, there is always the possibility that some user might overflow
it. If you set it large enough, say 4096, that probability is very low (although
not 0.0). In such cases it is often sufficient to just detect that fact (which
can easily be done: just look for a '\n' character in Buffer) and ask the user
for less input.

--
Karl Heinz Buchegger
kb******@gascad.at
Nov 14 '05 #9

P: n/a
Eric Sosman wrote:
cl********@aol.com wrote:
[scanf("%d") leaves the newline unconsumed]

This is solution temporarily OK'ed by boss:

#include <stdio.h>
int main()
{
int c;
int the_number;
char car_ret;

fprintf (stderr,"Enter Number :");

#ifdef __sgi
scanf ("%d",&the_number);
#elif defined (__linux)
scanf ("%d%c",&the_number,&car_ret);
#endif


Fragile; a house of cards. If the user enters anything
at all between the final digit and the newline -- a space
character, say -- you'll be right back where you started.
I'll repeat my earlier advice: scanf() is not well suited
for interactive input, and you'd be better off using another
method altogether.


Actually, used properly scanf is quite suitable, as long as you are
willing to have the overhead of that large interpreter.

/* get a numeric and flush the input line */
/* return 0 for success, non-zero otherwise */
int getnum(int *num)
{
int ok, ch;

ok = scanf("%d", num);
while (EOF != (ch = getchar()) && ('\n' != ch)) continue;
return (1 == ok);
}

although I would never use it in that form. I keep a separate
flushln(f) function about, and would simply write:

if (1 == scanf("%d", &num)) .....
if (EOF == flushln(stdin)) .....

as long as people realize that leading blanks and empty lines will
be skipped. The key to suitable use of scanf interactively is the
"if (1 == scanf(....". Anything other than one leads to confusion,
gnashing of teeth, and loss of hair. The advantage is the
elimination of presized buffers.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
Nov 14 '05 #10

P: n/a
Richard Herring <ju**@[127.0.0.1]> wrote:
pete <pf*****@mindspring.com>
#include <stdio.h>
int main()
{
int c;
int the_number;
fprintf (stderr,"Enter Number :");
scanf ("%d",&the_number);
fprintf (stderr,"\nEnter a letter :");


Oh, I see. Well, the answer would be "yes", though personally, since
this is crossposted to clc++ I'd prefer cerr.

The user may have redirected stdout to a file or piped it to another
program, so they wouldn't see prompts directed to it. And stderr is
automatically flushed, so if you're lucky the prompts will appear before
the input operation starts.


If, yes. If you're unlucky, though, stderr will appear in the console
window, not in the user's main window, and he'll completely overlook it.
The sysadmin, OTOH, will be pissed off at you for spamming his log files
with completely meaningless messages. stderr is for error messages, not
for prompts. Besides, if stdout _is_ redirected, that was intentional.

Richard
Nov 14 '05 #11

P: n/a
In message <42***************@news.xs4all.nl>, Richard Bos
<rl*@hoekstra-uitgeverij.nl> writes
Richard Herring <ju**@[127.0.0.1]> wrote:
>> pete <pf*****@mindspring.com>
>>> #include <stdio.h>
>>> int main()
>>> {
>>> int c;
>>> int the_number;
>>> fprintf (stderr,"Enter Number :");
>>> scanf ("%d",&the_number);
>>> fprintf (stderr,"\nEnter a letter :");
Oh, I see. Well, the answer would be "yes", though personally, since
this is crossposted to clc++ I'd prefer cerr.

The user may have redirected stdout to a file or piped it to another
program, so they wouldn't see prompts directed to it. And stderr is
automatically flushed, so if you're lucky the prompts will appear before
the input operation starts.


If, yes. If you're unlucky, though, stderr will appear in the console
window,


What is a "console window"?
not in the user's main window, and he'll completely overlook it.
Just as he would if he redirected stdout to a file, or piped it to
another program.
The sysadmin,
What is a "sysadmin"?
OTOH, will be pissed off at you for spamming his log files
with completely meaningless messages.
Even back in the days when I had to manage a mainframe system, I don't
recall messages to stderr from user programs ever going anywhere but the
user's teletype. But yes, it's true that the way the standard streams
are connected to the hardware is beyond the scope of the C or C++
standards, so anything could happen.
stderr is for error messages, not
for prompts.
And stdout is for computed output, not for prompts. In the absence of a
stdprompt, one has to use one or the other, and the decision is not best
made on the basis of its name but on how it interacts with the outside
world.
Besides, if stdout _is_ redirected, that was intentional.


Of course. It's not something one does by accident. But intentions
differ.

--
Richard Herring
Nov 14 '05 #12

P: n/a
Richard Herring <ju**@[127.0.0.1]> wrote:
In message <42***************@news.xs4all.nl>, Richard Bos
<rl*@hoekstra-uitgeverij.nl> writes
The sysadmin,


What is a "sysadmin"?


Someone you are obviously in dire need of.

HTH; HAND.

Richard
Nov 14 '05 #13

P: n/a
In message <42***************@news.xs4all.nl>, Richard Bos
<rl*@hoekstra-uitgeverij.nl> writes
Richard Herring <ju**@[127.0.0.1]> wrote:
In message <42***************@news.xs4all.nl>, Richard Bos
<rl*@hoekstra-uitgeverij.nl> writes
>The sysadmin,


What is a "sysadmin"?


Someone you are obviously in dire need of.


What was your username again?

--
Richard "clickety click" Herring
Nov 14 '05 #14

This discussion thread is closed

Replies have been disabled for this discussion.