0

I have the following simple code:

#include <iostream>
int main()
{
   int a;
   std::cout << "enter integer a" << std::endl;
   std::cin >> a ;

   if (std::cin.fail())
   {
      std::cin.clear();
      std::cout << "input is not integer, re-enter please" <<std::endl;
      std::cin >>a;
      std::cout << "a inside if is: " << a <<std::endl;
   }
   std::cout << "a is " << a <<std::endl;
   std::cin.get();
   return 0;
}

When I run the above code and input: 1.5, it outputs: a is 1. FYI: I compile and run the code with gcc 4.5.3.

This means that if cin expects an integer but sees a float, it will do the conversion implicitly. So does this mean that when cin sees a float number, it is not in fail() state? Why this is the case? Is it because C++ does implicit conversion on >> operator?

I also tried the following code to decide whether a given input number is integer following idea from this post: testing if given number is integer:

#include <iostream>
bool integer(float k)
{
    if( k == (int) k) return true;
    return false;
}

int main()
{
   int a;
   std::cout << "enter integer a"<< std::endl;
   std::cin >> a ;

   if (!integer(a))
   {
     std::cout << "input is not integer, re-enter please" ;
     std::cin.clear();
     std::cin >> a;
     std::cout << "a inside if is: " << a <<std::endl;
   }
   std::cout << "a is " << a <<std::endl;
   std::cin.get();
   return 0;
}

This block of code was also not able to test whether a is integer since it simply skip the if block when I run it with float input.

So why this is the case when getting user input with cin? What if sometimes I want the input to be 189, but typed 18.9 by accident, it will result in 18 in this case, which is bad. So does this mean using cin to get user input integers is not a good idea?

thank you.

Community
  • 1
  • 1
taocp
  • 23,276
  • 10
  • 49
  • 62
  • line 4. int a; ---> double a; – enhzflep Mar 24 '13 at 03:56
  • 1
    If you take the input `a` as a float instead of an int, then check if `a == (int)a` that would tell you if it was an integer, also. – Aiias Mar 24 '13 at 03:57
  • cin "knows" what type it is reading, and does different things depending on the type. For an int, it reads digits, and stops as soon as it sees a non-digit. It is *not* reading the entire "1.2" in your example, it stops after the "1", because the next character is not a digit. – Chris Hartman Mar 24 '13 at 04:01

3 Answers3

6

When you read an integer and you give it an input of 1.5, what it sees is the integer 1, and it stops at the period since that isn't part of the integer. The ".5" is still in the input. This is the reason that you only get the integer part and it is also the reason why it doesn't seem to wait for input the second time.

To get around this, you could read a float instead of an integer so it reads the whole value, or you could check to see if there is anything else remaining on the line after reading the integer.

Vaughn Cato
  • 63,448
  • 5
  • 82
  • 132
1

When reading user input I prefer not to use operator>> as user input is usally line based and prone to errors. I find it best to read a line at a time and validate:

 std::string   line;
 std::getline(std::cin, line);

This also makes it easy to check for different types of numbers.

 std::stirngstream linestream(line);
 int  val;
 char c;

 if ((linestream >> val) && !(linestream >> c))
 {
     // Get in here if an integer was read.
     // And there is no following (non white space) characters.
     // i.e. If the user only types in an integer.
     // 
     // If the user typed any other character after the integer (like .5)
     // then this will fail.
}

Of course boost already supports this:

val = boost::lexical_cast<int>(linestream); // Will throw if linestream does 
                                            // not contain an integer or
                                            // contains anything in addition
                                            // to the integer.

Boost of course will convert floats as well.

Martin York
  • 257,169
  • 86
  • 333
  • 562
1

I have some snippet which is kind a poor coding, but it works. This method is pretty simple, but doesn't handle case when input value is invalid. See more: https://en.cppreference.com/w/cpp/string/byte/atof

static float InputFloat(std::string label)
{
    std::string input;
    std::cout << label;
    std::cin >> input;
    return atof(input.c_str());
}

int main()
{
    float value = InputFloat("Enter some float value: ");
    std::cout << "value = " << value;
    return 0;
}