2

Hello i'm trying to use a do-while loop to check the input and repeat the prompt until the user types in a correct integer. So that's my code:

#include <iostream>
#include <stdio.h>
#include <ctype.h>    

int main ()
{

  int a;

  do
  {
     printf("Please type in your number: ");
  }while(scanf_s("%d", &a) == 0); 

  std::cin.get();
  std::cin.get();

  return 0;
}

Well it seems to work. When I type in a number the program runs correctly. But when I type in a letter an infinite loop starts. Sincerly I don't know where the problem is.

6
  • 7
    scanf will keep trying to scan for an int, but a letter will make it stop, and that letter will remain in the buffer until it's consumed/flushed. A common issue - stackoverflow.com/questions/1716013/scanf-causing-infinite-loop Commented Nov 10, 2010 at 6:14
  • 5
    You probably want to choose EITHER the iostream library OR the cstdio library for i/o purposes. Commented Nov 10, 2010 at 6:18
  • 2
    Tagged with visual-c++ because of use of the Microsoft specific scanf_s function. Commented Nov 10, 2010 at 6:22
  • Well i can't use "std::cin.get()" without the iostream and i don't know another way to hold the screen so that i can see the result. Commented Nov 10, 2010 at 6:23
  • 2
    @Ordo: The equivalent to std::cin::get is getchar Commented Nov 10, 2010 at 6:37

7 Answers 7

4

Again, I suggest reading a line into a string and then trying to parse that string according to your needs. If the parse fails, simply prompt the user again. You can bury the messy details in a function template:

#include <iostream>
#include <sstream>
#include <string>

template <typename T>
T read(std::string prompt)
{
    for (; ;)
    {
        std::cout << prompt;
        std::string line;
        getline(std::cin, line);
        std::istringstream ss(line);
        T x;
        if ((ss >> x) && (ss >> std::ws).eof()) return x;
    }
}

int main ()
{
    int a = read<int>("Please type in your number: ");
    std::cout << "You entered " << a << '\n';
}
Sign up to request clarification or add additional context in comments.

2 Comments

That's nice and thorough, but paints a gloomy picture of C++ usability... :-.
Thanks for your advise but that wonderful piece of code is just to complicated for me. I'm just a beginner and i don't understand most of it.
3

Here's what's going on -- I'll go through step by step. Starting from the do:

  1. output: Please type in your number:
  2. call to scanf Scanf finds that stdin is empty, and therefore waits for a line to be typed in.
  3. input : letter (note that the input buffer now contains "letter")
  4. scanf attempts to parse the string as an integer. Parsing fails before it consumes any characters. Therefore the buffer still contains "letter"
  5. scanf returns EOF (error)
  6. output: Please type in your number:
  7. call to scanf -- scanf sees that there's already waiting input in stdin
  8. scanf attempts to parse the buffer as an integer.....

This will go on forever because scanf will never consume the characters from the buffer. You can solve the problem by correctly checking for an error return code from scanf.

4 Comments

-1 I'm afraid. scanf_s() will never return EOF because there is always still a character in the buffer -- it will return 0, because that was the number of fields successfully converted. Also you don't say how to overcome this case -- you will need to read characters (e.g. with getchar() in a loop) until \n or EOF is seen.
@j_random_hacker: I believe I did not say scanf_s in my answer. I believe I said scanf, which returns EOF upon any failure, including "failures" that are not EOF.
Both functions (scanf() and scanf_s()) return EOF only when attempting to read a character results in EOF on the input stream or some other filesystem-level error. If characters can be read but don't match the next input field, this is regarded as "success" and the number of fields successfully read (possibly 0) is returned. The docs I found (e.g. cplusplus.com/reference/clibrary/cstdio/scanf) don't make it as clear as I've tried to here, but the fact that they say that scanf() is explicitly allowed to return 0 implies this.
I verified this by looking at scanf("%d", &x)'s return value in 2 different cases: (1) User types 'A' -> result 0. (2) Input redirected from /dev/null -> result -1 (== EOF). Same answer from MSVC++2010 and g++ 4.1.2 on Linux.
0

First of all never ever use scanf as its one hell of a dangerous function.

If you want to stick with C you should use fgets to read the input from the user to a buffer and then atoi to convert the input from the user to an integer.

Note: fgets always adds the 'enter' in to the buffer so you want to strip it off before converting the content of the buffer.

this could be easily done as follow:

_buffer[strlen(_buffer)-1] = '\0';

12 Comments

There's no reason to avoid scanf unless you are trying to read strings with it. For things like reading numbers it's perfectly fine.
@Billy ONeal: Agree with your 1st comment, but the 2nd...? That construction is unsafe because it's possible to read a string of length 0, but there's no problem with "compiler support" AFAICT.
@j_random_hacker: The code psicho proposes chooses an array size at runtime. That is a C99 feature (variable length arrays). It's not valid in C89, and would require dynamic allocation instead.
@Billy: you can provide upper-bounds on data to read into strings - nothing inherently unsafe about it then either - just that too many people don't bother to be that careful.
@Billy ONeal: It's pretty obviously not a declaration of an array but an assignment to an element of a pre-existing array. (Which carries buffer overrun and, here, underrun risk -- but no language issues.)
|
0

I have modified my code so that it works now. But sincerly it just works for numbers and letters. I want it to work with every char. For example "!?%". I have already tried to change the "isalnum" by "isascii" but that does not work.

#include <stdio.h>
#include <ctype.h>

int main ()
  {

    int a;
    int b = 1;
    char c ;

    do
    { 
      printf("Please type in a number: ");

      if (scanf("%d", &a) == 0)
      {
        printf("Your input is not correct\n");
        do 
        {
          c = getchar();
        }
        while (isalnum(c));  
        ungetc(c, stdin);    
      }
      else
      { 
      printf("Thank you! ");
      b--;
      }

    }
    while(b != 0); 

    getchar();
    getchar();

    return 0;
  }

Comments

0

@ ordo

Blockquote

I have modified my code so that it works now. But sincerly it just works for numbers and letters. I want it to work with every char. For example "!?%". I have already tried to change the "isalnum" by "isascii" but that does not work.

Blockquote

You can use

if(userInput>='!'&& userInput<= '~') // refer ASCII chart between !and ~. { exit=0; }

http://www.cdrummond.qc.ca/cegep/informat/professeurs/alain/images/ASCII1.GIF

Comments

-1
int main ()
{    
  int a;
  char userInput,exit=1;

  do
  {
     printf("Please type in your number: ");
     userInput=getch();

     if(userInput=='1') // suppose the correct input is 1.
     { exit=0; }         

  }while(exit); 

  std::cin.get();
  std::cin.get();

  return 0;
}

If the input is between 0 and 9...

 if(userInput>='0'&& userInput<= '9') // suppose the correct input is 1.
    { exit=0; }

Note that we have to use ' ' signs

Comments

-2

You can use getchar() function

do
  {
     printf("Please type in your number: ");
  }while((getchar() - '0') == 0); 

4 Comments

Why - '0' == 0? How is that different than just getchar() == '0'? More importantly, this fails for numbers which contain more than one digit.
That would keep looping until they typed in the character '0' (of course it has line buffering issues, so they might need to hit return too). I think the post wants to get any number (e.g. 0, 1, 12, -423).
@Tony: What if my number is 101?
@Billy: sorry, my comment wasn't addressing yours - I should have prefixed my comment with @Alien01, but like you I started writing it thinking it'd be the first comment on the proposed answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.