0

I'm trying to check validity of user input like so:

#include<iostream>
#include<cstdlib>
int main(){

    int val =0;
    std::cout<<"222 to quit"<<std::endl;
    while(true){
        if(std::cin>>val)
        {
             if(val == 222)
                break;
            std::cout<<"Valid Input"<<std::endl;
        }
        else
        {
            std::cout<<"Invalid Input"<<std::endl;
            std::cin.clear();
            fflush(stdin);
           
        }
       
    }
    system("pause");

}

basically when the input is an int, it should be declared valid; and invalid otherwise. It works perfectly for int and char: int and char inputs But when a float is provided, it shows two outputs- both valid and invalid! float input Can someone help me understand what's happening here?

I expected it to say 'invalid' input for floats.

MMudhol
  • 9
  • 3
  • What is the value of `val` at the moment "Valid Input" is output? (Use a debugger, or add some output to show you it.) – JaMiT Feb 02 '23 at 06:07
  • You can read it as a string and check for the presence of decimal point – balu Feb 02 '23 at 06:13
  • @JaMiT: When the input is 1.2, `val` is 1 at first and the `if` routine is executed. When the `if` block is done with, `val` is now zero (possibly invalid `cin`) and it executes the `else` block. – MMudhol Feb 02 '23 at 06:26
  • Don't pass an input-only `FILE*` (like `stdin`) to `fflush`, it leads to *undefined behavior*. There are better ways in C++. Like reading *whole lines* into a string, then then attempt to parse the string (with for example [`std::stoi`](https://en.cppreference.com/w/cpp/string/basic_string/stol)). – Some programmer dude Feb 02 '23 at 06:42
  • 1
    Using `std::cin >> val` doesn't work well if the input isn't consistent with the type of `val` - and users are notorious for supplying inconsistent input. If `val` is an `int`, and the input is `1.2`, the `1` will be read (so `val` will get a value `1`) and reading stops, leaving the `'.'` in the input buffer and placing the steam into an error state. Next time an `int` is read, the error state and buffered `'.'` are encountered..... So it is usually better to read all input as a string, and validate (check and correct) the string BEFORE trying to extract a value from the string. – Peter Feb 02 '23 at 06:42
  • @peter: the stream is not put into an error state until the second attempt to read an `int`. If you instead do `cin>>intval; cin>>strval;` (or just `cin>>intval>>strval;`), then `intval` is 1, `strval` is `".2"`, and `cin` is good. – rici Feb 02 '23 at 07:00
  • @Someprogrammerdude- `cin.ignore()` doesn't seem to work, where as `fflush(stdin)` always clears the input buffer, so I used it. – MMudhol Feb 02 '23 at 07:04
  • Problem is it doesn't always clear the input. Because the behaviour is undefined, one implementation could clear the buffer, another could outright ignore the instruction, a third could crash, and a some completely crazy implementation could teleport your cat to Mars. If the implementation clearly documents exactly what'll happen, you can trust it on that one implementation. Your code won't necessarily port to other systems, though. – user4581301 Feb 02 '23 at 07:06
  • @rici Thanks for the clarification. I recalled that, after the second and subsequent reads, the stream will be in an error state (and couldn't recall - or check the docs - to see whether it would be in an error state after the first read) – Peter Feb 02 '23 at 07:06
  • @MMudhol `fflush()` actually gives undefined behaviour for any input streams. Yes, some implementations of the standard library use it to clear input buffers, but not all do. That unreliability (even if you are willing to live with undefined behaviour) means that `fflush(stdin)` is not a good idea in practice. – Peter Feb 02 '23 at 07:09
  • @user4581301- so what is a reliable way to clear the input buffer? – MMudhol Feb 02 '23 at 07:09
  • Sadly there isn't one. If you know there is data in the stream, you can `ignore`. But if there is no data in the stream the ignore will block for more data to arrive (and then throw out at least some of this new data) or the stream to close. streaming IO is very, very simple stuff because it has to work exactly the same on a computer with a dull terminal emulator and a little embedded system that uses a Dorito for a CPU and standard in is a dumb-as-a-post serial port. When you need to do fancy stuff, you have to use a fancier tool. – user4581301 Feb 02 '23 at 07:14
  • Generally the most reliable thing to do is read whole lines at a time and then parse the lines. Something like [option 2 in this answer](https://stackoverflow.com/a/7868998/4581301). – user4581301 Feb 02 '23 at 07:16
  • https://en.cppreference.com/w/cpp/io/basic_istream/ignore The page includes a simple example. Also see https://en.cppreference.com/w/cpp/io/basic_ios/clear which also has an example. – rici Feb 02 '23 at 07:19
  • @MMudhol *"`val` is 1 at first"* -- this is valuable debugging info. You should get in the habit of digging (at least) this deep into your bugs. -- *"(possibly invalid `cin`)"* -- Recognizing this possibility is good. Next, you "just" have to put these pieces together. With "just" in quotation marks because the process is not obvious until you practice enough. (Recognize that `1` was pulled from the input stream, leaving `.` as the next character. So the next read into an integer starts with `.`. Hypothesize that this might have led to the speculated "invalid" result.) – JaMiT Feb 03 '23 at 04:02

0 Answers0