Search code examples
c++iostreamcin

why would cin.fail() pass input=100a if 'input' is an int?


int main(void)
{
   int valid_input();
   int ll_input=0;
   int resp;
   hash_table obj;
   int bucket;  
   while(1)
   {
      ll_input=valid_input();
      if(ll_input>10)
      {
        break;
      }
      obj.insert(ll_input);

   }
   obj.print_ll();


   return 0;
}    

int valid_input()

{
  int input;
  printf("\n\rEnter the value: ");
  std::cin >> input;
  while(std::cin.fail())
  {
    std::cin.clear();
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
    printf("\n\rBad entry!\n\rEnter the value: ");
    std::cin>>input;
  }
  return input;
}

The above is the code, it works correctly for most alphanumeric combinations, it rejects user inputs like a,10aa,1003abc, etc. However, it on inputs like 100a, 100b, etc, passes. What could the reason be for this?

The following is the output in the snapshot enter image description here


Solution

  • cin >> input stops reading as soon as it finds any non number, so "100a" is interpreted as two tokens: "100" and "a".

    "100" is converted into an int and exits the while(std::cin.fail()) loop. This leaves "a" sitting in the stream to bedevil the next read of cin.

    The quick way to catch this, (quick in terms of writing and explaining, not the fastest to execute if the input is error-prone)

    std::string token;
    while (true) // or a countdown to kick out the truly moronic
    {
        cin >> token;
        try
        {
            size_t pos;
            int result = std::stoi(token, &pos);
            if (pos == token.size())
            {
                 return result;
            }
        }
        catch (...) // don't really care why std::stoi failed
        {
        }
    }
    

    std::stoi documentation.

    Faster approaches, if errors are expected, use strtol or similar and skip the exception handling overhead.