Gnijuohz
Gnijuohz

Reputation: 3364

what happens when you input things like 12ab to scanf("%d",&argu)?

I came across this problem when I want to check what I input is number. The scanf function will return 1 if I successfully input a number. So here is what I wrote:

int argu;
while(scanf("%d",&argu)!=1){
    printf("Please input a number!\n");
}

But when I input things like abcd to it, the loop would go forever and not stop for prompt.

I looked it up online and found that it had something to do with the cache and I need to clean it up so scanf can get new data. So I tried fflush but it didn't work.

Then I saw this:

int argu,j;
while(scanf("%d",&argu)!=1){
    printf("Please input a number!\n");
    while((j=getchar())!='\n' && j != '\n');
}

Then when I input things like 'abcd' it worked well and it prompted for my input. But when I input things like '12ab', it wouldn't work again.

So is there a way I can check the input for scanf("%d", &argu) is actually a number and prompt for another input if it isn't?

EDIT:

I saw the answers and solved my problem by using while(*eptr != '\n').

Notice that the fgets function actually reads '\n' into the array and gets doesn't. So be careful.

Upvotes: 5

Views: 3802

Answers (5)

Spidey
Spidey

Reputation: 2589

Just call scanf("%*[^\n]\n") inside the loop, and it will discard the "cache".

Upvotes: 0

Alex Lockwood
Alex Lockwood

Reputation: 83303

Call scanf("%*[^\n]\n") inside the loop. This should be enough to discard anything associated with the cache.

Upvotes: -1

John Bode
John Bode

Reputation: 123448

But when I input things like abcd to it, the loop would go forever and not stop for prompt.

That's because if scanf encounters a character that does not match the conversion specifier, it leaves it in the input stream. Basically, what's happening is that scanf reads the character a from the input stream, determines that it's not a valid match for the %d conversion specifier, and then pushes it back onto the input stream. The next time through the loop it does the same thing. And again. And again. And again.

fflush is not a good solution, because it isn't defined to work on input streams.

For the input "12ab", scanf will read and convert "12", leaving "ab" in the input stream.

The best solution is to read all your input as text, then convert to numeric types using strtol (for integral values) and strtod (for real values). For example:

char input[SIZE]; // assume SIZE is big enough for whatever input we get
int value;

if (fgets(input, sizeof input, stdin) != NULL)
{
  char *chk;
  int tmp = (int) strtol(input, &chk, 10);
  if (isspace(*chk) || *chk == 0)
    value = tmp;
  else
    printf("%s is not a valid integer string\n", input);
}

chk points to the first character in the input stream that isn't a decimal digit. If this character is not whitespace or the 0 terminator, then the input string wasn't a valid integer. This will detect and reject inputs like "12ab" as well as "abcd".

scanf is a good solution if you know your input is always going to be properly formed and well-behaved. If there's a chance that your input isn't well-behaved, use fgets and convert as needed.

Upvotes: 2

unwind
unwind

Reputation: 399793

It's better to read a full line, using fgets(), and then inspecting it, rather than trying to parse "on the fly" from the input stream.

It's easier to ignore non-valid input, that way.

Use fgets() and then just strtol() to convert to a number, it will make it easy to see if there is trailing data after the number.

For instance:

char line[128];

while(fgets(line, sizeof line, stdin) != NULL)
{
   char *eptr = NULL;
   long v = strtol(line, &eptr, 10);
   if(eptr == NULL || !isspace(*eptr))
   {
     printf("Invalid input: %s", line);
     continue;
   }
   /* Put desired processing code here. */
}

Upvotes: 4

nav_jan
nav_jan

Reputation: 2553

I will suggest to get input as a string and check for non-numeric characters in it. If input is valid convert string to int by sscanf(str,"%d",&i); or else diplay error.

Upvotes: 1

Related Questions