Search code examples
c++user-input

Why does a C++ mathematical operation accept a letter as an input and output a number?


I'm brand new to c++, so maybe this is a stupid question, but I coded a very simple temperature conversion program. It looks like this:

#include <iostream>

int main() {
  
  double tempf;
  double tempc;
  
  // Ask the user
  std::cout << "Enter the temperature in Fahrenheit: ";
  std::cin >> tempf;
  
  // Conversion
  tempc = (tempf - 32) / 1.8;
  
  // Print Output  
  std::cout << "The temp is " << tempc << " degrees Celsius.\n";
  
}

This compiles and runs fine when I enter an integer/float as an input. However, out of curiosity, I tried entering a letter, expecting to get an error or a failure of some kind. Instead, after compiling, I get this output:

$ g++ temperature.cpp -o temp
$ ./temp
Enter the temperature in Fahrenheit: abc
The temp is -17.7778 degrees Celsius.

Can someone tell me where the executable is getting the output -17.7778 from? This seems like an arbitrary number, not a mathematical output.


Solution

  • "However, out of curiosity, I tried entering a letter, expecting to get an error or a failure of some kind."

    By default, std::cin reports errors by setting internal error bits that must be checked manually. One mechanism is to use the good() member function to check for any error bits. Another is to use the bool conversion operator which does the same thing, it will convert to true is no error bits are set, otherwise it converts to false.

    Example :

    if(!std::cin) {
        std::cout << "Input error!";
        return;
    }
    

    When std::cin fails, it will assign the value 0 to the variable.

    From cppreference.com :

    If extraction fails (e.g. if a letter was entered where a digit is expected), zero is written to value and failbit is set.

    When you provide the input "abc" the expression std::cin >> tempf; will fail to read anything, assign 0 to tempf and set a fail bit. Then, during tempc = (tempf - 32) / 1.8; the value calculated will be (0.0 - 32) / 1.8 which is approximately -17.7778 which is the result you observe.

    You can change the default behavior to throw an exception on failure by using the exceptions member function. But beware that if other parts of your project use std::cin and don't expect this change it can disrupt their error handling scheme which may rely on checking error bits.

    The example provided by cppreference.com for this example :

    #include <iostream>
    #include <fstream>
     
    int main() 
    {
        int ivalue;
        try {
            std::ifstream in("in.txt");
            in.exceptions(std::ifstream::failbit); // may throw
            in >> ivalue; // may throw
        } catch (const std::ios_base::failure& fail) {
            // handle exception here
            std::cout << fail.what() << '\n';
        }
    }