473,616 Members | 2,970 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

scanf behaviour

Hello.

I maybe reinvent the weel ...
I'm trying to read positive integer number with the help of scanf, if
the input value is not positive number but negaive one zero or char , i
have to reread the input until I get the needed pos. number

I wrote the code , but it doesn't work the way it should : if i put
some char into input, the program goes infinite loop instead of
promting me to enter a new value.

Please shed some light on what is the problem. thanks
Expand|Select|Wrap|Line Numbers
  1. #include <stdio.h>
  2.  
  3. int main()
  4. {
  5. int n;
  6. while (1)
  7. {
  8. printf("Please enter positive number \n");
  9. if ( scanf("%d",&n)!=1 || n<=0 )
  10. {
  11. printf("Illegal input!\n");
  12. continue;
  13. }
  14.  
  15. return 0;
  16. }
  17. return 1;
  18. }
  19.  
Nov 24 '06 #1
68 4599
st******@gmail. com wrote:
Hello.

I maybe reinvent the weel ...
I'm trying to read positive integer number with the help of scanf, if
the input value is not positive number but negaive one zero or char , i
have to reread the input until I get the needed pos. number

I wrote the code , but it doesn't work the way it should : if i put
some char into input, the program goes infinite loop instead of
promting me to enter a new value.
That's because the conversion fails and the characters remain in the
stream. So the next time scanf is called, the same character sequence is
read.

Add

fflush( stdin );

after your printf.
Please shed some light on what is the problem. thanks
Expand|Select|Wrap|Line Numbers
  1. #include <stdio.h>
  2. int main()
  3. {
  4.     int n;
  5.     while (1)
  6.     {
  7.         printf("Please enter positive number \n");
  8.         if ( scanf("%d",&n)!=1 || n<=0 )
  9.         {
  10.             printf("Illegal input!\n");
  11.             continue;
  12.         }
  13.     return 0;
  14.     }
  15. return 1;
  16. }
  17.  

--
Ian Collins.
Nov 24 '06 #2
Ian Collins said:
Add

fflush( stdin );
No, don't do that. The behaviour of fflush on streams open for input is
undefined.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Nov 24 '06 #3
Richard Heathfield wrote:
Ian Collins said:

>>Add

fflush( stdin );


No, don't do that. The behaviour of fflush on streams open for input is
undefined.
Oops, so it is.

I've always used the Solaris man page definition:

"If stream points to an input stream or an update stream into
which the most recent operation was input, that stream is
flushed if it is seekable and is not already at end-of-file."

--
Ian Collins.
Nov 24 '06 #4
st******@gmail. com wrote:
I maybe reinvent the weel ...
No, you just found out that scanf() is not very well suited for
dealing with user input. You're definitely not the first and
won't be the last;-)
I'm trying to read positive integer number with the help of scanf, if
the input value is not positive number but negaive one zero or char , i
have to reread the input until I get the needed pos. number
I wrote the code , but it doesn't work the way it should : if i put
some char into input, the program goes infinite loop instead of
promting me to enter a new value.
Please shed some light on what is the problem. thanks
#include <stdio.h>
int main()
int main( void )

tends to be better since your main() function doesn't take any input.
{
int n;
while (1)
{
printf("Please enter positive number \n");
if ( scanf("%d",&n)! =1 || n<=0 )
The problem you're facing is that when scanf() doesn't find what
it's looking for it won't read anything at all. So if the user inputs
something that doesn't start with a number (with optionally a '+' or
'-' in front of it) it stops immediately and nothing of the users
input gets consumed. When scanf() then tries to read again it still
finds the same characters it couldn't deal with already the last time
and bails out again. Repeat at nauseam...

In this case there are two ways t deal with it. The probably saner
approach is to use a function like fgets() to read the input as a
string, analyze this string for a number you are prepared to accept,
and then to use e.g. strtol() to get at that number (which also allows
to do full error checking).

But since you're here just looking for a positive integer there's
the following alternative:

#include <stdio.h>

int main( void )
{
char buffer[10];
int x ;

do {
printf( "Please enter positive number\n" );
while ( scanf( "%9[^-+0-9]", buffer ) != 0 )
/* empty */ ;
} while ( scanf( "%d", &x ) != 1 || x <= 0 );
printf( "Got %d", x );
return 0;
}

The scanf() in the while loop consumes all non-numerical input
(except '+' and '-') and then the scanf() in the do loops
condition tries to read in an integer. If that works and the
number is positive the loop ends. If not we're back to square
one. But there's still the problem that you can't check if the
user input a number that's too large to be stored in an integer.
Such checks can only be done using the approach mentioned first.
And, of course, it also will return 123 for e.g. "asa%#123.1 2"
(and leaves everything following the "123" in the input buffer)
- I don't know if that's what you want.

Regards, Jens
--
\ Jens Thoms Toerring ___ jt@toerring.de
\______________ ____________ http://toerring.de
Nov 25 '06 #5
Jens Thoms Toerring wrote:
st******@gmail. com wrote:
>I maybe reinvent the weel ...

No, you just found out that scanf() is not very well suited for
dealing with user input. You're definitely not the first and
won't be the last;-)
>I'm trying to read positive integer number with the help of scanf,
if the input value is not positive number but negaive one zero or
char , i have to reread the input until I get the needed pos. number
>I wrote the code , but it doesn't work the way it should : if i put
some char into input, the program goes infinite loop instead of
promting me to enter a new value.
.... snip code using scanf ...
>
The scanf() in the while loop consumes all non-numerical input
(except '+' and '-') and then the scanf() in the do loops
condition tries to read in an integer. If that works and the
number is positive the loop ends. If not we're back to square
one. But there's still the problem that you can't check if the
user input a number that's too large to be stored in an integer.
Such checks can only be done using the approach mentioned first.
And, of course, it also will return 123 for e.g. "asa%#123.1 2"
(and leaves everything following the "123" in the input buffer)
- I don't know if that's what you want.
ONLY be done? See the following. No buffers needed. Improved
since the published version. I am not completely happy with the
treatment of negative values in readxint. Also it needs to be
revised to use longs as the fundamental input mechanism. Note the
GPL licence.

/* ------------------------------------------------- *
* 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 "

/* For licensing restrictions (GPL) see readme.txt in:
* <http://cbfalconer.home .att.net/download/txtio.zip>
*
* These stream input routines are written so that simple
* conditionals can be used:
*
* if (readxint(&myin t, stdin)) {
* do_error_recove ry; normally_abort_ to_somewhere;
* }
* else {
* do_normal_thing s; usually_much_lo nger_than_bad_c ase;
* }
*
* 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 terminating
* char (including '\n'). Thus a sequence such as:
*
* err = readxint(&myint , stdin);
* flushln(stdin);
*
* will always consume complete lines, and after execution of
* readxint a further getc (or fgetc) will return the character
* that terminated the numeric field.
*
* 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.
*
* Originally issued 2002-10-07
*
* Revised 2006-01-15 so that unsigned entry overflow (readxwd)
uses the normal C modulo (UINT_MAX + 1) operation. readxwd
still rejects an initial sign as an error.
*/

/* -------------------------------------------------------------
* Skip to non-blank on f, and return that char. or EOF The next
* char that getc(f) will return is unknown. Local use only.
*/
static int ignoreblks(FILE *f)
{
int ch;

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

/*--------------------------------------------------------------
* 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)
{
return ungetc(ignorebl ks(f), 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(ch));
return ungetc(ch, f);
} /* skipwhite */

/*--------------------------------------------------------------
* Read an unsigned value. Signal error for overflow or no
* valid number found. Returns 1 for error, 0 for noerror, EOF
* for EOF encountered before parsing a value.
*
* Skip all leading blanks 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, 0 result, and the next 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 '-'.
*/
int readxwd(unsigne d 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 */

ch = ignoreblks(f);

if (EOF == ch) status = EOF;
else if (isdigit(ch)) status = 0; /* digit, no error */

while (isdigit(ch)) {
digit = ch - '0';
if ((value UWARNLVL) ||
((UWARNLVL == value) && (digit UWARNDIG))) {
status = 1; /* overflow */
value -= UWARNLVL;
}
value = 10 * value + digit;
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 blanks 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, 0 result, and the next 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;

ch = ignoreblks(f);

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

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

if (0 == status) {
/* got initial digit and no readxwd overflow */
if (!negative && (value <= INT_MAX))
*val = value;
else if (negative && (value < UINT_MAX) &&
((value - 1) <= -(1 + INT_MIN)))
*val = -value;
else { /* overflow */
status = 1; /* do whatever the native system does */
if (negative) *val = -value;
else *val = value;
}
}
else if (negative) *val = -value;
else *val = value;
}
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 */

--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home .att.net>

Nov 25 '06 #6
CBFalconer <cb********@yah oo.comwrote:
Jens Thoms Toerring wrote:
st******@gmail. com wrote:
I'm trying to read positive integer number with the help of scanf,
if the input value is not positive number but negaive one zero or
char , i have to reread the input until I get the needed pos. number
I wrote the code , but it doesn't work the way it should : if i put
some char into input, the program goes infinite loop instead of
promting me to enter a new value.
... snip code using scanf ...

The scanf() in the while loop consumes all non-numerical input
(except '+' and '-') and then the scanf() in the do loops
condition tries to read in an integer. If that works and the
number is positive the loop ends. If not we're back to square
one. But there's still the problem that you can't check if the
user input a number that's too large to be stored in an integer.
Such checks can only be done using the approach mentioned first.
And, of course, it also will return 123 for e.g. "asa%#123.1 2"
(and leaves everything following the "123" in the input buffer)
- I don't know if that's what you want.
ONLY be done? See the following. No buffers needed. Improved
since the published version. I am not completely happy with the
treatment of negative values in readxint. Also it needs to be
revised to use longs as the fundamental input mechanism. Note the
GPL licence.
<code snipped>

Thanks for the correction. What I actually wanted to warn the OP
about is that using only scanf() it's impossible to do full error
checking. As you have shown, using fgets() isn't the only method
that can be used here. And your code is a good example of what one
have to take into account to get it RIGHT;-) Unfortunately, when
one has to read in floating point numbers it probably will become
very difficult (or impossible?) to work with a single look-ahead
character and I guess then some solution involving fgets() will be
necessary. Or do you have a nice function also for that case?

Regards, Jens
--
\ Jens Thoms Toerring ___ jt@toerring.de
\______________ ____________ http://toerring.de
Nov 25 '06 #7
Thanks for reply.
I give it I try.
If this method is working only on flavours of unix , it's fine with me.

Ian Collins wrote:
Richard Heathfield wrote:
Ian Collins said:

>Add

fflush( stdin );

No, don't do that. The behaviour of fflush on streams open for input is
undefined.
Oops, so it is.

I've always used the Solaris man page definition:

"If stream points to an input stream or an update stream into
which the most recent operation was input, that stream is
flushed if it is seekable and is not already at end-of-file."

--
Ian Collins.
Nov 25 '06 #8
Thanks Jens .

I have to use scanf() because of my task's constrains.
Your work-around works fine, if "fflush(std in)" idea from previuos post
would fail,
i would surely go for it.

Thanks for the tip.

Jens Thoms Toerring wrote:
st******@gmail. com wrote:
I maybe reinvent the weel ...

No, you just found out that scanf() is not very well suited for
dealing with user input. You're definitely not the first and
won't be the last;-)
I'm trying to read positive integer number with the help of scanf, if
the input value is not positive number but negaive one zero or char , i
have to reread the input until I get the needed pos. number
I wrote the code , but it doesn't work the way it should : if i put
some char into input, the program goes infinite loop instead of
promting me to enter a new value.
Please shed some light on what is the problem. thanks
#include <stdio.h>
int main()

int main( void )

tends to be better since your main() function doesn't take any input.
{
int n;
while (1)
{
printf("Please enter positive number \n");
if ( scanf("%d",&n)! =1 || n<=0 )

The problem you're facing is that when scanf() doesn't find what
it's looking for it won't read anything at all. So if the user inputs
something that doesn't start with a number (with optionally a '+' or
'-' in front of it) it stops immediately and nothing of the users
input gets consumed. When scanf() then tries to read again it still
finds the same characters it couldn't deal with already the last time
and bails out again. Repeat at nauseam...

In this case there are two ways t deal with it. The probably saner
approach is to use a function like fgets() to read the input as a
string, analyze this string for a number you are prepared to accept,
and then to use e.g. strtol() to get at that number (which also allows
to do full error checking).

But since you're here just looking for a positive integer there's
the following alternative:

#include <stdio.h>

int main( void )
{
char buffer[10];
int x ;

do {
printf( "Please enter positive number\n" );
while ( scanf( "%9[^-+0-9]", buffer ) != 0 )
/* empty */ ;
} while ( scanf( "%d", &x ) != 1 || x <= 0 );
printf( "Got %d", x );
return 0;
}

The scanf() in the while loop consumes all non-numerical input
(except '+' and '-') and then the scanf() in the do loops
condition tries to read in an integer. If that works and the
number is positive the loop ends. If not we're back to square
one. But there's still the problem that you can't check if the
user input a number that's too large to be stored in an integer.
Such checks can only be done using the approach mentioned first.
And, of course, it also will return 123 for e.g. "asa%#123.1 2"
(and leaves everything following the "123" in the input buffer)
- I don't know if that's what you want.

Regards, Jens
--
\ Jens Thoms Toerring ___ jt@toerring.de
\______________ ____________ http://toerring.de
Nov 25 '06 #9
st******@gmail. com said:
Thanks for reply.
I give it I try.
Why? It's wrong, broken, wrong, broken, wrong, wrong, wrong! Why would you
use a wrong, broken, wrong, broken, wrong, wrong, wrong suggestion? Even
the guy who suggested it now realises it's wrong, broken, wrong, broken,
wrong, wrong, wrong.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Nov 25 '06 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

5
3881
by: Eduardo Olivarez | last post by:
The following code does not work correctly on my machine. Either one of the scanf()'s alone work perfectly. However, when they are combined, the second scanf() call just reads what the first one received as imput, without taking any keyboard input and then the process terminates prematurely. I looked through the glibc documentation trying to figure out what was causing this to no avail, so I started messing around with the code. Strangely...
14
2722
by: Peter Mount | last post by:
Hello I'm having trouble with " scanf("%c", &answer);" on line 20 below. When I run the program in cygwin on Windows 98SE it skips that line completely and ends the program. Does scanf have problems with "%c" or is it the operating system I'm using? 1 #include <stdio.h> 2 3 int main()
7
7652
by: hugo27 | last post by:
obrhy8 June 18, 2004 Most compilers define EOF as -1. I'm just putting my toes in the water with a student's model named Miracle C. The ..h documentation of this compiler does state that when scanf cannot fill any fields it returns EOF. I have run some tests on scanf and, so far, I've not found an EOF return. For example: If the programer formats scanf for an int or
18
1567
by: Radith | last post by:
HI all; I have created a program just to get an understanding of strcpy. (still an amateur developer). I use scanf("%s", &first) in order to get the input to the variable first (which is char first). Then I go strcpy(second, first). This is just to demonstrate the strcpy function for myself and it (as far as I know) copies what's in first to
33
3123
by: Lalatendu Das | last post by:
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 ()
7
1760
by: sajjanharudit | last post by:
Can anyone explain me what is happening in the following code: #include<stdio.h> int main() { int i,j; scanf("%d %d" + scanf("%d %d",&i,&j)); printf("%d %d\n"); }
30
3182
by: James Daughtry | last post by:
char array; scanf("%19s", &array); I know this is wrong because it's a type mismatch, where scanf expects a pointer to char and gets a pointer to an array of 20 char. I know that question 6.12 of the C FAQ says that it's wrong for that very reason. What I don't know is where the standard tells me conclusively that it's wrong. What I also don't know is somewhere that this type mismatch will break in practice.
62
5003
by: Argento | last post by:
I was curious at the start about how ungetc() returns the character to the stream, so i did the following coding. Things work as expected except if I change the scanf("%c",&j) to scanf("%d",&j). I don't understand how could scanf() affect the content of i and i. Can someone tell me why? #include <stdio.h> #include <ctype.h> void main() {
27
2270
by: guoliang | last post by:
help: #include<stdio.h> int main(void) { int a; char b; printf("int=");
3
9833
by: Tinku | last post by:
#include<stdio.h> main() { char line; scanf("%", line); printf("%s", line); } it will read and print the line but what is "%" in general we gives %s, %c .
0
8203
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
8146
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
8647
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
8592
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
8297
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
1
6097
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
5550
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
4141
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
1759
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.