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

confused about behaviour of scanf

P: n/a
Dear friends,
I am getting a problem in the code while interacting with a nested
Do-while loop
It is skipping a scanf () function which it should not. I have written
the whole code below. Please help me in finding why such thing is
happening and what the remedy to it is. Kindly bear with my English.
int
main ()
{
int num1[4] , i = 0 ;
char ch ;

do
{
do
{
printf ("Enter the number in the array \n");
scanf("%d",&num[i] );
i++;
} while (i<=3);

printf("Do u want to refill the array again y/n
\n");
scanf ("%c", &ch); /* This line is skipped, it
is not
prompting to
give input
from keyboard
*/

} while (ch = = 'y') ; /* In gdb 'ch' is
showing the value same as
it has at the time of declaration i.e.
some garbage */

return 0;
}

I know this is very silly question for many of u but still I am in
ambiguity to resolve it . So please send me all possible way of
resolving it. and why such problem occurring. The environment in which
I have done it is gcc-3.2.2, red hat Linux -9 , debugged using gdb .

Dec 21 '05 #1
Share this Question
Share on Google+
33 Replies


P: n/a
add fflush(stdin) to clear input buffer

int main ()
{
int num[4] , i = 0 ;
char ch ;

do
{
do
{
printf ("Enter the number in the array \n");
scanf("%d",&num[i] );
i++;
} while (i<=3);

fflush(stdin);
printf("Do u want to refill the array again y/n\n");
scanf ("%c", &ch);
} while (ch == 'y') ;

return 0;

}

Dec 21 '05 #2

P: n/a
On 2005-12-21, alok <al******@gmail.com> wrote:
add fflush(stdin) to clear input buffer


No.
Dec 21 '05 #3

P: n/a
Hi Lalatendu,

There's a '\n' remainning in input stream after the outer loop, it then
was read by scanf ("%c", &ch). (you can see it in gdb just after this
line).

You can use fflush(stdin) to clean the unwanted '\n' before scanf next
value.

Matt

Dec 21 '05 #4

P: n/a
Matt wrote:
Hi Lalatendu,

There's a '\n' remainning in input stream after the outer loop, it then
was read by scanf ("%c", &ch). (you can see it in gdb just after this
line).

You can use fflush(stdin) to clean the unwanted '\n' before scanf next
value.

Matt

Well, it looks like we're two-for-two on answers to this thread (but at
least *this* poster found part of the solution.

fflush() is only defined for *output* streams. In this case a simple
getc() would suffice to read (and discard) the trailing newline character.

Just as an aside, this is one of the reasons why scanf() shoul dprobably
be avoided in most cases. A call to fgets() followed by a call to
sscanf() is typically preferred.

HTH,
--ag

--
Artie Gold -- Austin, Texas
http://goldsays.blogspot.com
http://www.cafepress.com/goldsays
"If you have nothing to hide, you're not trying!"
Dec 21 '05 #5

P: n/a
Lalatendu Das wrote:
Dear friends,
I am getting a problem in the code while interacting with a nested
Do-while loop
It is skipping a scanf () function which it should not. I have written
the whole code below. Please help me in finding why such thing is
happening and what the remedy to it is. Kindly bear with my English.
int
main ()
{
int num1[4] , i = 0 ;
char ch ;

do
{
do
{
printf ("Enter the number in the array \n");
scanf("%d",&num[i] );
i++;
} while (i<=3);

printf("Do u want to refill the array again y/n
\n");
scanf ("%c", &ch); /* This line is skipped, it
is not
prompting to
give input
from keyboard
*/

} while (ch = = 'y') ; /* In gdb 'ch' is
showing the value same as
it has at the time of declaration i.e.
some garbage */

return 0;
}

I know this is very silly question for many of u but still I am in
ambiguity to resolve it . So please send me all possible way of
resolving it. and why such problem occurring. The environment in which
I have done it is gcc-3.2.2, red hat Linux -9 , debugged using gdb .


See the comp.lang.c FAQ 12.17, 12.18a, 12.19, 12.20 and search
the comp.lang.c archives.

Note: fflush(stdin) is _not_ the solution. getchar() can be.

Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
Dec 21 '05 #6

P: n/a
i m running this program in MS VC++ & after using fflush(stdin) , it
is working fine .
so y fflush(stdin) is _not_ the solution ?

Dec 21 '05 #7

P: n/a
i m running this program in MS VC++ & Solaris gcc after using
fflush(stdin) , it is working fine .
so y fflush(stdin) is _not_ the solution ?

Dec 21 '05 #8

P: n/a
[Corrected quoting]
--- Quoting from others ---------
<Quote>
It is proper Usenet etiquette to include the relevant portions of the
text you are replying to. To do this using Google groups, please follow
the instructions below, penned by Keith Thompson:

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.
</Quote>

alok wrote:
Michael Mair wrote:
See the comp.lang.c FAQ 12.17, 12.18a, 12.19, 12.20 and search
the comp.lang.c archives.

Note: fflush(stdin) is _not_ the solution. getchar() can be.

Cheers
Michael


i m running this program in MS VC++ & Solaris gcc after using
fflush(stdin) , it is working fine .
so y fflush(stdin) is _not_ the solution ?


Because the standard says so
C99 7.19.5.2
"
Ifstream points to an output stream or an update stream in which the
most recent operation was not input, the fflush function causes any
unwritten data for that stream to be delivered to the host environment
to be written to the file; otherwise, the behavior is undefined.
"

Since it is undefined anything can happen. It might be working for you
now and it might be the feature of the compiler not the language.

--
(Welcome) http://www.ungerhu.com/jxh/clc.welcome.txt
(clc FAQ) http://www.eskimo.com/~scs/C-faq/top.html
Dec 21 '05 #9

P: n/a
In article <11**********************@g47g2000cwa.googlegroups .com>,
alok <al******@gmail.com> wrote:
i m running this program in MS VC++ & after using fflush(stdin) , it
is working fine .
so y fflush(stdin) is _not_ the solution ?


Welcome to clc.

Dec 21 '05 #10

P: n/a

"Anand" <An***@no-replies.com> wrote in message
news:05************@news.oracle.com...
[Corrected quoting]
--- Quoting from others ---------
<Quote>
It is proper Usenet etiquette to include the relevant portions of the text
you are replying to. To do this using Google groups, please follow the
instructions below, penned by Keith Thompson:

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.
</Quote>

alok wrote:
Michael Mair wrote:
See the comp.lang.c FAQ 12.17, 12.18a, 12.19, 12.20 and search
the comp.lang.c archives.

Note: fflush(stdin) is _not_ the solution. getchar() can be.

Cheers
Michael


i m running this program in MS VC++ & Solaris gcc after using
fflush(stdin) , it is working fine .
so y fflush(stdin) is _not_ the solution ?


Because the standard says so
C99 7.19.5.2
"
Ifstream points to an output stream or an update stream in which the most
recent operation was not input, the fflush function causes any unwritten
data for that stream to be delivered to the host environment to be written
to the file; otherwise, the behavior is undefined.
"

Since it is undefined anything can happen. It might be working for you now
and it might be the feature of the compiler not the language.


It would be sooo simple if there were a way to test stdin for
eof/empty-buffer :-)
Dec 21 '05 #11

P: n/a
On 21 Dec 2005 00:29:21 -0800, "alok" <al******@gmail.com> wrote:
i m running this program in MS VC++ & after using fflush(stdin) , it
is working fine .
so y fflush(stdin) is _not_ the solution ?


it s nt the sltn because fflush is defined only for output streams .
Calling fflush for an input stream invokes undefined behavior. One of
the unluckiest manifestations of undefined behavior is the appearance
of working as expected and thereby misleading you to think it is
correct. This usually lasts until you have to demo the product to
your boss or a client.

The discussion of MS VC++ features/anomalies/ is properly done in one
of the microsoft.*.* groups. This group is about standard C
<<Remove the del for email>>
Dec 21 '05 #12

P: n/a

pemo wrote:
"Anand" <An***@no-replies.com> wrote in message
news:05************@news.oracle.com... []

alok wrote: []
i m running this program in MS VC++ & Solaris gcc after using
fflush(stdin) , it is working fine .
so y fflush(stdin) is _not_ the solution ?


Because the standard says so
C99 7.19.5.2

[]
It would be sooo simple if there were a way to test stdin for
eof/empty-buffer :-)


There is
while ( !fgets( buffer, size, STDIN) ) { ...
or
while ( !(nextch=getchar()) ) { ...

Do people not read the documentation of the functions they use?
ed

Dec 21 '05 #13

P: n/a
Ed Prochak wrote:
pemo wrote:
"Anand" <An***@no-replies.com> wrote in message
news:05************@news.oracle.com...
[]
alok wrote:
[]
i m running this program in MS VC++ & Solaris gcc after using
fflush(stdin) , it is working fine .
so y fflush(stdin) is _not_ the solution ?
Because the standard says so
C99 7.19.5.2


[]
It would be sooo simple if there were a way to test stdin for
eof/empty-buffer :-)

There is
while ( !fgets( buffer, size, STDIN) ) { ...

ITYM: stdin or
while ( !(nextch=getchar()) ) { ... ITYM: EOF != (nextch = getchar())
Do people not read the documentation of the functions they use?


"Real men don't need to read the manual" or, in this case, the
documentation... ;-(

Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
Dec 21 '05 #14

P: n/a
alok wrote:
i m running this program in MS VC++ & Solaris gcc after using
fflush(stdin) , it is working fine .
so y fflush(stdin) is _not_ the solution ?


Apart from the missing context: Please try to write something
resembling written English, especially write whole words.

As others have told you: fflush(stdin) has no defined behaviour
from the standard C point of view.

Slighty off-topic example:
Consider the many breaking changes from MSVC++6 to
MSVC++2003 and 2005 which nearly all concern the change from
not standard-conforming to standard-conforming behaviour (especially
for the C++ part). If the people relying on non-standard stuff had
written the things as standard-conforming as possible, they would
not have had to rewrite huge parts of their code.

So, as there exists a perfectly portable and viable solution to
your problem, it is reasonable to use it instead of a solution
which may not work after a change of platform, operating system,
compiler or even compiler version.

Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
Dec 21 '05 #15

P: n/a
Ed Prochak wrote:
pemo wrote:
"Anand" <An***@no-replies.com> wrote in message
news:05************@news.oracle.com... []
alok wrote: [] i m running this program in MS VC++ & Solaris gcc after using
fflush(stdin) , it is working fine .
so y fflush(stdin) is _not_ the solution ?

Because the standard says so
C99 7.19.5.2

[]
It would be sooo simple if there were a way to test stdin for
eof/empty-buffer :-)


There is
while ( !fgets( buffer, size, STDIN) ) { ...
or
while ( !(nextch=getchar()) ) { ...


Neither of your suggestions tests for an empty buffer for an empty
buffer since the functions you are calling will just sit there until
either there is something in the buffer or they detect an end-of-file or
error condition. Your use of getchar is completely wrong, since it
returns EOF, not 0, or either end-of-file or error. You don't attempt to
distinguish between an error and end-of-file (which can be done).
Do people not read the documentation of the functions they use?


Obviously not.

Standard C provides no mechanism for detecting whether there is anything
in the buffer ready to be read, which I consider to be a shame. It
would, IMHO, be useful if standard C had a bufempty function with four
return values, empty, non-empty, full and unknown, but it does not exist
in standard C.
--
Flash Gordon
Living in interesting times.
Although my email address says spam, it is real and I read it.
Dec 21 '05 #16

P: n/a
"Ed Prochak" <ed********@magicinterface.com> writes:
pemo wrote:
"Anand" <An***@no-replies.com> wrote in message
news:05************@news.oracle.com...

[]
>
> alok wrote: [] >> i m running this program in MS VC++ & Solaris gcc after using
>> fflush(stdin) , it is working fine .
>> so y fflush(stdin) is _not_ the solution ?
>>
>
> Because the standard says so
> C99 7.19.5.2

[]

It would be sooo simple if there were a way to test stdin for
eof/empty-buffer :-)


There is
while ( !fgets( buffer, size, STDIN) ) { ...
or
while ( !(nextch=getchar()) ) { ...


Which, as others have pointed out, doesn't check for an empty buffer.

A feature I've seen elsewhere is the ability to flush the input buffer
before reading input after a prompt. For example, given:

printf("Enter a string: ");
fflush(stdout); /* make sure the prompt appears */
flush_input_buffer(stdin);
fgets(s, LEN, stdin);

any characters typed by the user before the prompt appears would be
discarded. Ordinarily they'd be saved in the typeahead buffer; if the
user guessed wrong about wnat the next prompt was going to be, bad
things could happen.

C provides no standard way to do this, mostly because it doesn't
assume stdin is an interactive device such as a keyboard. <OT>I've
used systems that had this feature; I think it was FLUSH(INPUT); in
UCSD PAscal.</OT>

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Dec 21 '05 #17

P: n/a
Lalatendu Das wrote:
Dear friends,
I am getting a problem in the code while interacting with a nested
Do-while loop
It is skipping a scanf () function which it should not. I have written
the whole code below. Please help me in finding why such thing is
happening and what the remedy to it is. Kindly bear with my English.


The problem is that you have a stray newline character stuck in the
input stream after the first scanf(). For example, suppose you type
1234 at the prompt and hit Return. The input stream then contains the
characters '1', '2', '3', '4', and '\n'. The "%d" conversion specifier
tells scanf() to skip any leading whitespace, and to read and convert
all numeric (decimal) characters up to the first non-numeric character.
So the first scanf() reads the '1', '2', '3', and '4' characters from
the input stream and stops. This leaves the '\n' character still in
the input stream. The "%c" conversion specifier tells scanf() to read
and assign the next character. So the second scanf() call sees the
'\n' in the input stream and assigns it to ch, but to you it looks like
the second scanf() is being skipped.

There are several ways around this. The simplest option is to change
the second scanf() to use the "%s" conversion specifier and read a
string instead of a single character. The "%s" conversion specfier
will skip any leading whitespace, so stray newlines won't cause
problems (however, other stray characters might; that's a different
thread, though). It means changing ch from a single char to an array,
but that's no big deal:

char ch[2];
....
printf("Do you want to refill the array again y/n: ");
fflush(stdout);
scanf("%1s", ch);
if (ch[0] == 'y')
{
...
}

It's not a robust solution, but it'll get you past this particular
issue.
int
main ()
{
int num1[4] , i = 0 ;
char ch ;

do
{
do
{
printf ("Enter the number in the array \n");
scanf("%d",&num[i] );
i++;
} while (i<=3);

printf("Do u want to refill the array again y/n
\n");
scanf ("%c", &ch); /* This line is skipped, it
is not
prompting to
give input
from keyboard
*/

} while (ch = = 'y') ; /* In gdb 'ch' is
showing the value same as
it has at the time of declaration i.e.
some garbage */

return 0;
}

I know this is very silly question for many of u but still I am in
ambiguity to resolve it . So please send me all possible way of
resolving it. and why such problem occurring. The environment in which
I have done it is gcc-3.2.2, red hat Linux -9 , debugged using gdb .


Dec 21 '05 #18

P: n/a

Lalatendu Das wrote:
Dear friends,
I am getting a problem in the code while interacting with a nested
Do-while loop
It is skipping a scanf () function which it should not. I have written
the whole code below. Please help me in finding why such thing is
happening and what the remedy to it is. Kindly bear with my English.
int
main ()
{
int num1[4] , i = 0 ;
char ch ;

do
{
do
{
printf ("Enter the number in the array \n");
scanf("%d",&num[i] );
i++;
} while (i<=3);

printf("Do u want to refill the array again y/n
\n");
scanf ("%c", &ch); /* This line is skipped, it
is not
prompting to
give input
from keyboard
*/

} while (ch = = 'y') ; /* In gdb 'ch' is
showing the value same as
it has at the time of declaration i.e.
some garbage */

return 0;
}

I know this is very silly question for many of u but still I am in
ambiguity to resolve it . So please send me all possible way of
resolving it. and why such problem occurring. The environment in which
I have done it is gcc-3.2.2, red hat Linux -9 , debugged using gdb .


what if we use
scanf ("% c", &ch); //using a space between % and c
Does this help to eliminate the new line charater in the buffer????

Dec 21 '05 #19

P: n/a
Alok
whatever u have suggested is the same which came to my mind
also . but it fails when tried . it might work in vc++ or any other
but in redhat linux 9/ gcc 3.2.2 (as i have mentioned before) it fails
to work . so i need a solution which work for everything.

And have also asked one of my teacher about this then , he told me to
scan a pointer using fgets(). just before scanf it will eradicate the
problem .
char *test ;
test = (char *) malloc(11);
fgets( test , 11 , stdin);
though this works but this is not a rsonable and genuine way to
eradiacate the problem as where i will implement such things it will
going to change the design .

Dec 22 '05 #20

P: n/a
Thanks i found many good suggestions from the group and many
clarifications which i assumed wrong .

thanks to the group members

Dec 22 '05 #21

P: n/a

Flash Gordon wrote:
Ed Prochak wrote:
pemo wrote:
"Anand" <An***@no-replies.com> wrote in message
news:05************@news.oracle.com... []
alok wrote:

[]
> i m running this program in MS VC++ & Solaris gcc after using
> fflush(stdin) , it is working fine .
> so y fflush(stdin) is _not_ the solution ?
>
Because the standard says so
C99 7.19.5.2

[]
It would be sooo simple if there were a way to test stdin for
eof/empty-buffer :-)


There is
while ( !fgets( buffer, size, STDIN) ) { ...
or
while ( !(nextch=getchar()) ) { ...


Neither of your suggestions tests for an empty buffer for an empty
buffer since the functions you are calling will just sit there until
either there is something in the buffer or they detect an end-of-file or
error condition.


Empty buffer is what you might have After the return. This is not
realtime I/O or raw terminal I/O. If the OP wants that they need to
look elsewhere.
Your use of getchar is completely wrong, since it
returns EOF, not 0, or either end-of-file or error.
You are right. I did it quickly and should have double checked (I did
put in EOF originally but then for some reaon I thought it wasn simpler
this way. Too much thinking). Thanks for the catch.
You don't attempt to
distinguish between an error and end-of-file (which can be done).
He did not ask about error checking, that comes outside the loop.
Do people not read the documentation of the functions they use?
Obviously not.


I got sloppy on getchar(). my apologies to all.
Standard C provides no mechanism for detecting whether there is anything
in the buffer ready to be read, which I consider to be a shame. It
would, IMHO, be useful if standard C had a bufempty function with four
return values, empty, non-empty, full and unknown, but it does not exist
in standard C.
in the getchar() case there is no buffer.
in the fgets() case, you get an empty buffer (actually NO buffer) when
EOF is reached.
If you consider an empty buffer to be one with just a newline (and
terminator) then you might see that and you have to test for it
yourself.

It might have been nice if the fgets interface included returning the
length of the data put in the buffer, so somewhat agree on that point
(the "non-empty" condition.)

The full condition is easy enough to check since the newline is not in
the buffer in that case. (or would this be an "overflow" condition in
your view?).

most of the time, I'm not sure these return conditions (non-empty,
full, ...) are really useful.
--
Flash Gordon
Living in interesting times.
Although my email address says spam, it is real and I read it.


Thanks again for the watchful eye.
Ed.

Dec 23 '05 #22

P: n/a
Ed Prochak wrote:
Flash Gordon wrote:
Ed Prochak wrote:
pemo wrote:
"Anand" <An***@no-replies.com> wrote in message
news:05************@news.oracle.com...
[]
> alok wrote:
[]
>> i m running this program in MS VC++ & Solaris gcc after using
>> fflush(stdin) , it is working fine .
>> so y fflush(stdin) is _not_ the solution ?
>>
> Because the standard says so
> C99 7.19.5.2
[]
It would be sooo simple if there were a way to test stdin for
eof/empty-buffer :-)
There is
while ( !fgets( buffer, size, STDIN) ) { ...
or
while ( !(nextch=getchar()) ) { ... Neither of your suggestions tests for an empty buffer for an empty
buffer since the functions you are calling will just sit there until
either there is something in the buffer or they detect an end-of-file or
error condition.


Empty buffer is what you might have After the return.


Not if the user hits another key fast enough. Also, that does not help
you check if there is an empty buffer, because if you call fgets it will
wait until a line has been entered.
This is not
realtime I/O or raw terminal I/O. If the OP wants that they need to
look elsewhere.
Agreed. However, what pemo said, and I agree with, is that it would be
nice to be able to test if input is available.
Your use of getchar is completely wrong, since it
returns EOF, not 0, or either end-of-file or error.


You are right. I did it quickly and should have double checked (I did
put in EOF originally but then for some reaon I thought it wasn simpler
this way. Too much thinking). Thanks for the catch.


We all make mistakes :-)
You don't attempt to
distinguish between an error and end-of-file (which can be done).


He did not ask about error checking, that comes outside the loop.


Yes, but your loop, which you suggested would detect end of file, will
report end of file when it was actually an error condition, so it does
not meet what I read as being the specification.
Do people not read the documentation of the functions they use?

Obviously not.


I got sloppy on getchar(). my apologies to all.
Standard C provides no mechanism for detecting whether there is anything
in the buffer ready to be read, which I consider to be a shame. It
would, IMHO, be useful if standard C had a bufempty function with four
return values, empty, non-empty, full and unknown, but it does not exist
in standard C.


in the getchar() case there is no buffer.


Yes there is in general. Normally stdin is line buffered so even you use
getchar it *still* won't return until the user presses return.
in the fgets() case, you get an empty buffer (actually NO buffer) when
EOF is reached.
If you consider an empty buffer to be one with just a newline (and
terminator) then you might see that and you have to test for it
yourself.
No, I consider an empty buffer to be there is no input sitting there
ready to be returned immediately if you call an input function.
It might have been nice if the fgets interface included returning the
length of the data put in the buffer, so somewhat agree on that point
(the "non-empty" condition.)
That is absolutely nothing to do with the problem.

The problem is, will the input function (getchar, fgets or whatever)
return immediately if I call it or will it sit there until some data (or
an error or end-of-file) arrives from else where, be that else-where a
file, serial port, pipe or whatever stdin is fetching from.
The full condition is easy enough to check since the newline is not in
the buffer in that case. (or would this be an "overflow" condition in
your view?).

most of the time, I'm not sure these return conditions (non-empty,
full, ...) are really useful.


They are very useful if you want your program to process input if there
is input available but get on with something else if no input is
available, and this is not that uncommon a requirement.
--
Flash Gordon
Living in interesting times.
Although my email address says spam, it is real and I read it.
Dec 23 '05 #23

P: n/a
Maybe this is the solution.

#include <stdio.h>

int main ()
{
int num[4],i;
char ch;
do{
i=0; // Remember this
do{
printf("Enter the number in the array \n");
scanf("%d",&num[i]);
i++;
}while (i<=3);
printf("Do u want to refill the array again y/n \n");
getchar();
scanf ("%c", &ch);
} while (ch=='y');
return 0;
}

getchar is used to remove \n from stdin

Dec 24 '05 #24

P: n/a
Jack Davis wrote:
Maybe this is the solution.
Solution to what? Provide context please, see
http://cfaj.freeshell.org/google/
#include <stdio.h>

int main ()
{
int num[4],i;
char ch;
do{
i=0; // Remember this
do{
printf("Enter the number in the array \n");
scanf("%d",&num[i]);
i++;
}while (i<=3);
printf("Do u want to refill the array again y/n \n");
getchar();
scanf ("%c", &ch);
} while (ch=='y');
return 0;
}

getchar is used to remove \n from stdin


What if the user enters:
5 pounds
I don't think you will get the correct result then. As has been stated
many times here, the best way is generally to use fgets to read the line
and then parse it afterwards.
--
Flash Gordon
Living in interesting times.
Although my email address says spam, it is real and I read it.
Dec 24 '05 #25

P: n/a
Flash Gordon wrote:
Jack Davis wrote:

.... snip code using scanf interactively ...

getchar is used to remove \n from stdin


What if the user enters: 5 pounds I don't think you will get the
correct result then. As has been stated many times here, the
best way is generally to use fgets to read the line and then
parse it afterwards.


The general problem with that is that you must then provide a
buffer, and must still contend with the possibility of unabsorbed
line endings. It is possible to use scanf safely for numeric input
in interactive situations as follows:

int flushln(FILE *f)
{
int ch;

while ('\n' != (ch = getc(f)) && (EOF != ch)) continue;
return ch;
} /* flushln */

with this little thing available, you can now avoid all buffers for
numeric input with:

int thingwanted;

....
printf("%s", someprompt); fflush(stdout);
if (1 != scanf("%d", &thingwanted)) {
/* input error, take action */
}
else {
flushln(stdin);
/* use the data */
}

The critical thing is that scanf only attempts one item, so that
its return value is easily interpreted. Scanf also always leaves
the terminating char in the input stream, so flushln (barring EOF
or error) will always have a '\n' to terminate on.

Note that the caller to flushln can still detect EOF or error.

--
"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
More details at: <http://cfaj.freeshell.org/google/>
Dec 24 '05 #26

P: n/a
In article <qK********************@maineline.net>
Chuck F. <cb********@maineline.net> wrote:
The general problem with [fgets+sscanf] is that you must then provide a
buffer, and must still contend with the possibility of unabsorbed
line endings.
Of course, one can use your ggets(), plus sscanf().
It is possible to use scanf safely for numeric input in
interactive situations [using a line-eating getc-loop function and]
printf("%s", someprompt); fflush(stdout);
if (1 != scanf("%d", &thingwanted)) {
/* input error, take action */
}
else {
flushln(stdin);
/* use the data */
}

The critical thing is that scanf only attempts one item, so that
its return value is easily interpreted. Scanf also always leaves
the terminating char in the input stream, so flushln (barring EOF
or error) will always have a '\n' to terminate on.


This still has one undesirable behavior. Suppose the above asks
for a number, and (on a conventional system) we have the following
on a screen, with "_" representing the cursor input:

Pick a number: _

The user now presses the ENTER key (or the RETURN key, depending
on the keyboard). The screen now shows:

Pick a number:
_

The user presses ENTER many more times. The screen now shows:

_

What is the machine doing?

(The answer is: it is consuming white-space previous to the "%d"
conversion. Most scanf formats begin by consuming white-space,
and it does not matter how many blank lines, or lines containing
nothing but blanks, are included at this point. They are all
consumed.)

Using fgets() (or ggets()), the program itself gets control back
at the point the user presses ENTER, and can re-print the prompt,
or handle "no number entered" in some suitable fashion.

The scanf family of functions simply behaves badly for interactive
input. If it were a kid, it would be getting a lump of coal for
Christmas. :-) (This is also why the "sfio" library has a rather
different set of input directives. It is kind of a shame the C
Standards folks considered only the K&R scanf() and not the sfio
input functions.)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Dec 24 '05 #27

P: n/a
Chris Torek wrote:
Chuck F. <cb********@maineline.net> wrote:
The general problem with [fgets+sscanf] is that you must then
provide a buffer, and must still contend with the possibility
of unabsorbed line endings.


Of course, one can use your ggets(), plus sscanf().
It is possible to use scanf safely for numeric input in
interactive situations [using a line-eating getc-loop function .... snip ...
The critical thing is that scanf only attempts one item, so
that its return value is easily interpreted. Scanf also
always leaves the terminating char in the input stream, so
flushln (barring EOF or error) will always have a '\n' to
terminate on.


This still has one undesirable behavior. Suppose the above asks
for a number, and (on a conventional system) we have the
following on a screen, with "_" representing the cursor input:


.... snip discussion of white space absorption nuisance ...

Then you can use the following routines, which are probably more
efficient than loading the whole schmeer of scanf interpretation
anyhow. The following again avoids the assignment of a buffer.

(These are directed at the thread, not at Chris Torek, who knows
very well how to build bulletproof i/o routines)

(I also seem to remember something dodgy about inputting -INTMAX
with these)

#ifndef H_txtinput_h
#define H_txtinput_h
# ifdef __cplusplus
extern "C" {
# endif

#include <stdio.h>

/* These stream input routines are written so that simple
* conditionals can be used:
*
* if (readxint(&myint, stdin)) {
* do_error_recovery; normally_abort_to_somewhere;
* }
* else {
* do_normal_things; usually_much_longer_than_bad_case;
* }
*
* They allow overflow detection, and permit other routines to
* detect the character that terminated a numerical field. No
* string storage is required, thus there is no limitation on
* the length of input fields. For example, a number entered
* with a string of 1000 leading zeroes will not annoy these.
*
* The numerical input routines *NEVER* absorb a terminal '\n'.
* Thus a sequence such as:
*
* err = readxint(&myint, stdin);
* flushln(stdin);
*
* will always consume complete lines.
*
* They are also re-entrant, subject to the limitations of file
* systems. e.g interrupting readxint(v, stdin) operation with
* a call to readxwd(wd, stdin) would not be well defined, if
* the same stdin is being used for both calls. If ungetc is
* interruptible the run-time system is broken.
*/

/*--------------------------------------------------------------
* Skip all blanks on f. At completion getc(f) will return
* a non-blank character, which may be \n or EOF
*
* Skipblks returns the char that getc will next return, or EOF.
*/
int skipblks(FILE *f);

/*--------------------------------------------------------------
* Skip all whitespace on f, including \n, \f, \v, \r. At
* completion getc(f) will return a non-blank character, which
* may be EOF
*
* Skipblks returns the char that getc will next return, or EOF.
*/
int skipwhite(FILE *f);

/*--------------------------------------------------------------
* Read an unsigned value. Signal error for overflow or no
* valid number found. Returns true for error, false for noerror
*
* Skip all leading whitespace on f. At completion getc(f) will
* return the character terminating the number, which may be \n
* or EOF among others. Barring EOF it will NOT be a digit. The
* combination of error and the following getc returning \n
* indicates that no numerical value was found on the line.
*
* If the user wants to skip all leading white space including
* \n, \f, \v, \r, he should first call "skipwhite(f);"
*
* Peculiarity: This specifically forbids a leading '+' or '-'.
* Peculiarity: This forbids overflow, unlike C unsigned usage.
* on overflow, UINT_MAX is returned.
*/
int readxwd(unsigned int *wd, FILE *f);

/*--------------------------------------------------------------
* Read a signed value. Signal error for overflow or no valid
* number found. Returns true for error, false for noerror. On
* overflow either INT_MAX or INT_MIN is returned in *val.
*
* Skip all leading whitespace on f. At completion getc(f) will
* return the character terminating the number, which may be \n
* or EOF among others. Barring EOF it will NOT be a digit. The
* combination of error and the following getc returning \n
* indicates that no numerical value was found on the line.
*
* If the user wants to skip all leading white space including
* \n, \f, \v, \r, he should first call "skipwhite(f);"
*
* Peculiarity: an isolated leading '+' or '-' NOT immediately
* followed by a digit will return error and a value of 0, when
* the next getc will return that following non-digit. This is
* caused by the single level ungetc available.
*/
int readxint(int *val, FILE *f);

/*--------------------------------------------------------------
* Flush input through an end-of-line marker inclusive.
*/
void flushln(FILE *f);

# ifdef __cplusplus
}
# endif
#endif
/* End of txtinput.h */

/* ------------------------------------------------- *
* File txtinput.c *
* ------------------------------------------------- */

#include <limits.h> /* xxxx_MAX, xxxx_MIN */
#include <ctype.h> /* isdigit, isblank, isspace */
#include <stdio.h> /* FILE, getc, ungetc */
#include "txtinput.h"

#define UCHAR unsigned char

/* These stream input routines are written so that simple
* conditionals can be used:
*
* if (readxint(&myint, stdin)) {
* do_error_recovery; normally_abort_to_somewhere;
* }
* else {
* do_normal_things; usually_much_longer_than_bad_case;
* }
*
* They allow overflow detection, and permit other routines to
* detect the character that terminated a numerical field. No
* string storage is required, thus there is no limitation on
* the length of input fields. For example, a number entered
* with a string of 1000 leading zeroes will not annoy these.
*
* The numerical input routines *NEVER* absorb a terminal '\n'.
* Thus a sequence such as:
*
* err = readxint(&myint, stdin);
* flushln(stdin);
*
* will always consume complete lines.
*
* They are also re-entrant, subject to the limitations of file
* systems. e.g interrupting readxint(v, stdin) operation with
* a call to readxwd(wd, stdin) would not be well defined, if
* the same stdin is being used for both calls. If ungetc is
* interruptible the run-time system is broken.
*/

/*--------------------------------------------------------------
* Skip all blanks on f. At completion getc(f) will return
* a non-blank character, which may be \n or EOF
*
* Skipblks returns the char that getc will next return, or EOF.
*/
int skipblks(FILE *f)
{
int ch;

do {
ch = getc(f);
} while ((' ' == ch) || ('\t' == ch));
/* while (isblank((UCHAR)ch)); */ /* for C99 */
return ungetc(ch, f);
} /* skipblks */

/*--------------------------------------------------------------
* Skip all whitespace on f, including \n, \f, \v, \r. At
* completion getc(f) will return a non-blank character, which
* may be EOF
*
* Skipwhite returns the char that getc will next return, or EOF.
*/
int skipwhite(FILE *f)
{
int ch;

do {
ch = getc(f);
} while (isspace((UCHAR)ch));
return ungetc(ch, f);
} /* skipwhite */

/*--------------------------------------------------------------
* Read an unsigned value. Signal error for overflow or no
* valid number found. Returns true for error, false for noerror
*
* Skip all leading whitespace on f. At completion getc(f) will
* return the character terminating the number, which may be \n
* or EOF among others. Barring EOF it will NOT be a digit. The
* combination of error and the following getc returning \n
* indicates that no numerical value was found on the line.
*
* If the user wants to skip all leading white space including
* \n, \f, \v, \r, he should first call "skipwhite(f);"
*
* Peculiarity: This specifically forbids a leading '+' or '-'.
* Peculiarity: This forbids overflow, unlike C unsigned usage.
* on overflow, UINT_MAX is returned.
*/
int readxwd(unsigned int *wd, FILE *f)
{
unsigned int value, digit;
int status;
int ch;

#define UWARNLVL (UINT_MAX / 10U)
#define UWARNDIG (UINT_MAX - UWARNLVL * 10U)

value = 0; /* default */
status = 1; /* default error */

do {
ch = getc(f);
} while ((' ' == ch) || ('\t' == ch)); /* skipblanks */
/* while (isblank((UCHAR)ch)); */ /* for C99 */

if (!(EOF == ch)) {
if (isdigit((UCHAR)ch)) /* digit, no error */
status = 0;
while (isdigit((UCHAR)ch)) {
digit = (unsigned) (ch - '0');
if ((value < UWARNLVL) ||
((UWARNLVL == value) && (UWARNDIG >= digit)))
value = 10 * value + digit;
else { /* overflow */
status = 1;
value = UINT_MAX;
}
ch = getc(f);
} /* while (ch is a digit) */
}
*wd = value;
ungetc(ch, f);
return status;
} /* readxwd */

/*--------------------------------------------------------------
* Read a signed value. Signal error for overflow or no valid
* number found. Returns true for error, false for noerror. On
* overflow either INT_MAX or INT_MIN is returned in *val.
*
* Skip all leading whitespace on f. At completion getc(f) will
* return the character terminating the number, which may be \n
* or EOF among others. Barring EOF it will NOT be a digit. The
* combination of error and the following getc returning \n
* indicates that no numerical value was found on the line.
*
* If the user wants to skip all leading white space including
* \n, \f, \v, \r, he should first call "skipwhite(f);"
*
* Peculiarity: an isolated leading '+' or '-' NOT immediately
* followed by a digit will return error and a value of 0, when
* the next getc will return that following non-digit. This is
* caused by the single level ungetc available.
*/
int readxint(int *val, FILE *f)
{
unsigned int value;
int status, negative;
int ch;

*val = value = 0; /* default */
status = 1; /* default error */
negative = 0;

do {
ch = getc(f);
} while ((' ' == ch) || ('\t' == ch)); /* skipwhite */
/* while (isblank((UCHAR)ch)); */ /* for C99 */

if (!(EOF == ch)) {
if (('+' == ch) || ('-' == ch)) {
negative = ('-' == ch);
ch = getc(f); /* absorb any sign */
}

if (isdigit((UCHAR)ch)) { /* digit, no error */
ungetc(ch, f);
status = readxwd(&value, f);
ch = getc(f); /* This terminated readxwd */
}

if (negative && (value < UINT_MAX) &&
((value - 1) <= -(1 + INT_MIN))) *val = -value;
else if (value <= INT_MAX) *val = value;
else { /* overflow */
status = 1;
if (value)
if (negative) *val = INT_MIN;
else *val = INT_MAX;
}
}
ungetc(ch, f);
return status;
} /* readxint */

/*-----------------------------------------------------
* Flush input through an end-of-line marker inclusive.
*/
void flushln(FILE *f)
{
int ch;

do {
ch = getc(f);
} while (('\n' != ch) && (EOF != ch));
} /* flushln */

/* End of txtinput.c */

--
"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
More details at: <http://cfaj.freeshell.org/google/>
Dec 24 '05 #28

P: n/a
in comp.lang.c i read:

all your casts of ch to UCHAR are a waste of time -- mine to see it and
yours to write it; heck even the compiler's, and the cpu's if code was
emitted -- as the source of ch's value is getc, which provides exactly the
value semantics you (redundantly) specify with the cast.

in the readxwd and readxint functions you initially loop to skip blanks, yet
earlier you defined a blank skipping function -- why aren't you using it?
then again you specifically state that the user should skip blanks prior to
calling the functions if that is their desire, so those loops seem contrary.
digit = (unsigned) (ch - '0');


this cast is also unnecessary, not the least because ch passed an isdigit
test, but also because digit has type unsigned.

--
a signature
Dec 27 '05 #29

P: n/a

Flash Gordon wrote:
Ed Prochak wrote:
Flash Gordon wrote:
Ed Prochak wrote:
pemo wrote: []
Empty buffer is what you might have After the return.
Not if the user hits another key fast enough. Also, that does not help
you check if there is an empty buffer, because if you call fgets it will
wait until a line has been entered.
> This is not
realtime I/O or raw terminal I/O. If the OP wants that they need to
look elsewhere.


Agreed. However, what pemo said, and I agree with, is that it would be
nice to be able to test if input is available.

[]
Standard C provides no mechanism for detecting whether there is anything
in the buffer ready to be read, which I consider to be a shame. It
would, IMHO, be useful if standard C had a bufempty function with four
return values, empty, non-empty, full and unknown, but it does not exist
in standard C.


in the getchar() case there is no buffer.


Yes there is in general. Normally stdin is line buffered so even you use
getchar it *still* won't return until the user presses return.


I was speaking of the user's buffer, not the systems buffer. Again, If
you want raw I/O you'll have to look at other functions, outside the C
standard.
in the fgets() case, you get an empty buffer (actually NO buffer) when
EOF is reached.
If you consider an empty buffer to be one with just a newline (and
terminator) then you might see that and you have to test for it
yourself.
No, I consider an empty buffer to be there is no input sitting there
ready to be returned immediately if you call an input function.


No input available is EOF. The user hung up the line, closed his
terminal window, or powered down his terminal. You are waiting on a
user, a person. human response times are measured in seconds or longer.
The computer is operating in microseconds and shorter. In the end the
computer always has to wait.

And again, if you want raw I/O look elsewhere. Besides games there are
very few applications (e.g., factory controls or embedded devices) that
need raw I/O. I've done these types of applications. Usually they don't
use stdio functions. This type of operation is often OS dependent.
It might have been nice if the fgets interface included returning the
length of the data put in the buffer, so somewhat agree on that point
(the "non-empty" condition.)
That is absolutely nothing to do with the problem.

The problem is, will the input function (getchar, fgets or whatever)
return immediately if I call it or will it sit there until some data (or
an error or end-of-file) arrives from else where, be that else-where a
file, serial port, pipe or whatever stdin is fetching from.


yes that's the differrence. I don't see that as a problem 99% of the
time, so why should the interface be complicated to improve the few
cases that do need it.

here's a question for you: want your disc I/O unbuffered too?
(oops, sorry but you didn't read that last data block fast enough, it's
gone because the next block is ready right NOW)

Be careful what you ask for, you just might get it. 8^)
The full condition is easy enough to check since the newline is not in
the buffer in that case. (or would this be an "overflow" condition in
your view?).

most of the time, I'm not sure these return conditions (non-empty,
full, ...) are really useful.


They are very useful if you want your program to process input if there
is input available but get on with something else if no input is
available, and this is not that uncommon a requirement.


There are ways of dealing with this that don't invlove complicating the
C standard I/O interface.

I disagree that this is a common requirement. Give some examples of
applications where this is clearly a requirement (and not just a
nice-to-have feature). Does your new checkbook program really have
anything useful to do while the user is entering the dollar amount of
the deposit?

Finally, let's be clear: which buffer do you really want to know about?
the buffer in your keyboard hardware?
the keyboard driver buffer?
the OS I/O buffers?
your application's window buffer?
your application's C I/O buffer?
your application's buffer?
Which one?
Do you see that changing just the C I/O functions might not solve your
problem?

Ed

Dec 27 '05 #30

P: n/a
those who know me have no need of my name wrote:

in comp.lang.c i read:

all your casts of ch to UCHAR are a waste of time -- mine to see
it and yours to write it; heck even the compiler's, and the
cpu's if code was emitted -- as the source of ch's value is
getc, which provides exactly the value semantics you
(redundantly) specify with the cast.
True enough. However you know that any bugs are not due to passing
a negative non-EOF value to isspace etc. :-)
in the readxwd and readxint functions you initially loop to skip
blanks, yet earlier you defined a blank skipping function -- why
aren't you using it? then again you specifically state that the
user should skip blanks prior to calling the functions if that
is their desire, so those loops seem contrary.
The code for skipping blanks was put in because it seemed more
efficient, and the code was trivial. The other notation is if the
user wants to also skip whitespace, which includes newlines,
vertical tabs, etc. a-la scanf.
digit = (unsigned) (ch - '0');


this cast is also unnecessary, not the least because ch passed
an isdigit test, but also because digit has type unsigned.


Also true. However you seem to have failed to quote the relative
portions, thus making it hard, or even impossible, for others to
understand what you are talking about.

This code has been lying about for 5 years or so here, waiting for
me to get a round tuit and polish it up. That's why it is missing
the ability to handle floats, longs, etc. and has not been bullet
proofed for max negative values. I posted it to satisfy someone
who worried about the line skipping when using scanf, as a means of
avoiding pre-assigned buffers.

Your criticisms seem not to affect the validity of the code.

--
Some informative links:
news:news.announce.newusers
http://www.geocities.com/nnqweb/
http://www.catb.org/~esr/faqs/smart-questions.html
http://www.caliburn.nl/topposting.html
http://www.netmeister.org/news/learn2quote.html

Dec 27 '05 #31

P: n/a
in comp.lang.c i read:
those who know me have no need of my name wrote:
in comp.lang.c i read:
digit = (unsigned) (ch - '0'); this cast is also unnecessary, not the least because ch passed
an isdigit test, but also because digit has type unsigned.


Also true. However you seem to have failed to quote the relative
portions, thus making it hard, or even impossible, for others to
understand what you are talking about.


really? i described the test made against ch prior to this statement and
digit's type -- what is missing that would be needed for understanding?

further this statement exists exactly once in the large bulk of the
original post so is trivially easy to locate should a larger context be
desired. or are you saying that the references header is useless and i
should have copied in all the vastness just in case?
This code has been lying about for 5 years or so here, waiting for me
to get a round tuit and polish it up. Your criticisms seem not to affect the validity of the code.


i thought i'd (try to) help polish it. seems you don't like feedback.
sorry, i'll try to remember that, but hope that others still find value in
it.

--
a signature
Dec 27 '05 #32

P: n/a
those who know me have no need of my name wrote:
in comp.lang.c i read:
.... snip ...
Your criticisms seem not to affect the validity of the code.


i thought i'd (try to) help polish it. seems you don't like
feedback. sorry, i'll try to remember that, but hope that others
still find value in it.


On the contrary, I welcome criticism. On the other hand what I
read into the general tone of your comments put me off, possibly
unreasonably.

--
Some informative links:
news:news.announce.newusers
http://www.geocities.com/nnqweb/
http://www.catb.org/~esr/faqs/smart-questions.html
http://www.caliburn.nl/topposting.html
http://www.netmeister.org/news/learn2quote.html

Dec 28 '05 #33

P: n/a
On 21 Dec 2005 13:38:09 -0800, "ch*******@yahoo.com"
<ch*******@yahoo.com> wrote:

Lalatendu Das wrote: <snip classic FAQ 12.18'> what if we use
scanf ("% c", &ch); //using a space between % and c
Does this help to eliminate the new line charater in the buffer????


No. But if you use " %c" (space percent-c) it will skip all whitespace
(newline or other) and read the first non-whitespace char (if any).
- David.Thompson1 at worldnet.att.net
Jan 4 '06 #34

This discussion thread is closed

Replies have been disabled for this discussion.