-1

I am writing a program where I place a check like this:

int small;
cout<<"Small Pizza Price: "; 
cin>>small;
while(!isdigit(small)){
    cout<<"Small Pizza Price: ";
    cin>>small;
}

but when the user inputs a value other than integer the program just break. I want to place a check where the user only inputs an integer value.

  • 2
    You need to at least show the data type of your variables. The behavior of this code will change **completely** depending on the type of `small`, even if you don't think they are important you always need to show variable declarations. – Ben Voigt Jun 21 '21 at 14:27
  • 2
    `isdigit` checks whether a single *character* is a digit. (The digits are `'0'`, `'1'`, `'2'`, `'3'`, `'4'`, `'5'`, `'6'`, `'7'`, `'8'`, and `'9'`.) If `small` is an `int`, attempting to input anything except an integer sets the stream in an error state and you enter an infinite loop. – molbdnilo Jun 21 '21 at 14:29
  • What this suppose to do? – Marek R Jun 21 '21 at 14:55
  • Does this answer your question? [Avoiding infinite loop when a char is enter in place of int](https://stackoverflow.com/questions/27190382/avoiding-infinite-loop-when-a-char-is-enter-in-place-of-int) – Miraz Jun 22 '21 at 00:12

4 Answers4

3

You need to check if extraction of the int succeeded, and if it didn't, possibly clear() the fail state of the stream. cin.eof() and cin.bad() can be used to check if the stream is in an unrecoverable state or you can combine them both with std::ios::badbit | std::ios::eofbit and check if std::cin.rdstate() has any of those bits set.

Checking if extraction succeeds is usually done by checking the stream's state in boolean context, like so:

if(!std::cin) { // or  if(not std::cin)  "not" is an alternative to "!"
    // the stream is in a failed state
}

When you do formatted extraction from a stream with std::cin >> small, operator>> will return a reference to the stream, which makes extracting and then checking the state easy:

if(not(std::cin >> small)) { /* extraction failed */ }

Full example:

#include <iostream>
#include <limits>   // std::numeric_limits

int main() {
    int small;

    while(std::cout << "Small Pizza Price: " && not(std::cin >> small)) {
        // if(std::cin.eof() || std::cin.bad()) {    or:
        if(std::cin.rdstate() & (std::ios::badbit | std::ios::eofbit)) {
            std::cout << "aborted\n";
            return 1;
        }
        std::cout << "please enter a valid price\n";
        std::cin.clear();                            // clear the fail state
        // remove any lingering characters in the istream:
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    }

    // small read successfully
}
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • 1
    Where is `not` defined? – Tim Randall Jun 21 '21 at 14:47
  • 1
    @TimRandall [`not`](https://en.cppreference.com/w/cpp/language/operator_alternative) is defined in the language. It reverses the `bool` argument. It's the same as `!` but is easier to spot for people like me that often misses the `!`. :-) – Ted Lyngmo Jun 21 '21 at 14:47
  • 1
    @TimRandall that's one of the most well hidden features of C++. Here's a link: https://en.cppreference.com/w/cpp/language/operator_alternative – Mark Ransom Jun 21 '21 at 16:53
  • `if(std::cin.rdstate() & (std::ios::badbit | std::ios::eofbit))` can also be written as `if(std::cin.bad() || std.cin.eof())`, which might be easier for some people to understand. – Remy Lebeau Jun 21 '21 at 18:35
  • @RemyLebeau Yes, I mentioned those member functions in the text but I should probably include that option in the code too. Updated. – Ted Lyngmo Jun 21 '21 at 18:49
0

You do not show in your source the declaration of the variable, small. If it is a string, I am assume that the extraction operator will parse the stream up until it encounters whitespace. If you were to declare the "small" variable as an integer or float like value, than the stream extraction operator would attempt to parse an integer from the stream using the locale currently imbued in the stream. If that attempt to parse the stream fails, then the stream's error flag will be set and you can test it using the not "!" operator.

Jon Trauntvein
  • 4,453
  • 6
  • 39
  • 69
0

Assuming that you want the program to only take integer value for variable int small, these are some points I would want to point out.

  • When a char value is passed instead of int to the variable int small, the program shows undefined behavior/falls in infinite loop. What happens is cin goes into a failed state and that makes it ignore further calls to it, till the error flag and buffer are reset.

  • isdigit() only takes a single char, returns positive number if it holds a digit(char c='7'). If char doesn't hold a digit, function returns 0.


possible solution:

  • To check whether valid input type(in this case int) is taken via cin>>, we can check return value of cin. If input is invalid, cin will return false value and vice versa.

  • When invalid(non-digit in this case) input is taken instead of valid(int) we have to clear the cin and input buffer for further input. To do that, we can use:

        cin.clear();
        cin.ignore(100, '\n');//clear next 100 value from input buffer
  • As a solution to your problem, this function can be used to check whether input is valid. if not, it will keep taking input until a valid is found.
void get_Untill_Int(int* pInput)//keep taking input untill input is `int or float`
{
    cin>> *pInput;
    /*-----------check input validation----------------*/
    while (!cin) 
    {
        cin.clear();
        cin.ignore(100, '\n');
        cout<<"Invalid Input Type.\nEnter again: ";
        cin >>*pInput;
    }
    /*-----------checked input validation-------------*/
}

Final program

int small;
cout<<"Small Pizza Price: "; 
get_Untill_Int(&small);
Miraz
  • 343
  • 3
  • 15
-2

You can do a check while your variable is undefinde you're going to ask an input from the user like :

int small;

cout<<"Small Pizza Price: ";
while(small == NULL){

    cin>>small;
}

Since you have defined your small as an int, it will repeat to ask until it gets an valid int as input

Makus
  • 99
  • 1
  • 8
  • Depending on your development environment, this may never ask for an input. For example, the value of `small` may be initialized to 0xCCCCCCCC if it's a temporary variable created on the stack. – Tim Randall Jun 21 '21 at 14:44
  • `small` isn't _undefined_. It's _uninitialized_ and reading an uninitialized variable makes your program have undefined behavior. Also comparing with `NULL` is probably not what you want. You probably want `int small = 0;` and then `while(small == 0)` – Ted Lyngmo Jun 21 '21 at 14:55
  • comparing `int` with `NULL`? And it is initialized. Yes it compiles, but it doesn't do what is expected. – Marek R Jun 21 '21 at 14:57
  • @TedLyngmo so what would you do if the user wants 0 to be small ? – Makus Jun 22 '21 at 09:12
  • @Makus I'm not sure I understand the question. In your example, `small` is uninitialized when you read it (unless you propose making it a global which is not recommended). Reading uninitialized variables makes the program to have undefined behavior. If you initialize it (`int small{};` or `int small = 0;`) you should compare with the value you initialized it with, not `NULL` which is for comparing pointers. – Ted Lyngmo Jun 22 '21 at 10:12