3

so I'm pretty new to C++ and I'm doing an assignment for my class. I ran into a problem when trying to check if an input is a string or a double/int. So I made a basic program to test it

#include <iostream>
#include <string>
using namespace std;
int main(int argc, char *argv[])
{
    string hi;
    double hello;

    cin >> hello;

    if (!cin)
    {
        //Strings go here

        cin.clear();
        cin >> hi;
        cout << hi << endl;
    }
    else
    {
        cout << hello << endl;
    }

    cout << "Done!" << endl;
}

So it works for basically when inputting a letter (such as "j" or "a") or a number but when inputting "+" or "-" it waits for the next input then forces it through the string block, even if it is a number. However "*" or "/" are read as strings and don't cause that issue (I'm assuming since they aren't explicitly operators) I assume I am probably missing something. Thank you


Edit: I am testing with single types at a time (such as 123, 1 , d, +) without mixing types, so there won't be any inputs that have a double and a string

As per user4581301's suggestion, I'll put in some examples input and outputs

Inputs:Outputs

"Hello":"Hello"

123:123

"/":"/"

"+" (Input after: 2):"2"

  • 1
    Are you saying that the program doesn't read "+123" as a double, but *does* with "/123"? That is very hard to believe. – molbdnilo Mar 04 '20 at 20:41
  • The question is not really clear .. if I got the question right, you would need to make few checks for this. if there are only numbers, if there is a point somewhere in the string. If it is a valid string (for example, if there are numbers before and after the dot ) –  Mar 04 '20 at 20:50
  • 2
    In general, if the input you're expecting can be either text that's convertible to a number or text that isn't convertible to a number, and you want to handle both, you should read it into a string and see if you can parse it as a number. Don't rely on the error handling in the stream extractors to make this sort of distinction. – Pete Becker Mar 04 '20 at 20:51
  • @molbdnilo, Sorry I wasn't clear, I was testing with just "+" without mixing a number with it, so "/" would be a string, but if I inputted "+" it wouldn't automatically end the program and would wait for another input to be put in then count that as a string without the "+". Don't know if this comment helped – Shivum Kumar Mar 04 '20 at 20:51
  • @PeteBecker, so would the best way to do is by looping through a saved string and see if it contains an alpha, otherwise it is a int. Or does the stringstream have a function for it? Thank you – Shivum Kumar Mar 04 '20 at 20:56
  • 1
    [`std::stod`](https://en.cppreference.com/w/cpp/string/basic_string/stof) converts a string to a `double`. – Pete Becker Mar 04 '20 at 20:59
  • Ok, thank you. I'll just use that instead. – Shivum Kumar Mar 04 '20 at 21:01
  • 1
    Ok, I have tested this and it is an unintuitive result (at least to me). If you enter a * and then press enter the first cin fails and does NOT consume the input and when the second cin is called the * is successfully read as a string. If you enter a + and then press enter the first cin fails and DOES consume the input and when the second cin is called it blocks until you enter something and then reads it as a string. The question is why cin fails but still consumes the input when + and - are entered by themselves. I would have expected the characters to be pushed back to the stream... – Jerry Jeremiah Mar 04 '20 at 21:11
  • You should try to make a program that given a string recognizes if it is an integer or if it contains given characters. The eay you are trying to solve the problem may be undefined since the program is based on the premise that the errors give you the answer instead of identifiyng each type of input. – polmonroig Mar 04 '20 at 21:25
  • Ok, so I am reading the standard and extraction happens in three steps: step 1: determine the conversion operator (which doesn't apply to this) and step 2: extract as many characters as possible that could be part of a number (the + sign in this case) and step 3: try to make a valid number from the extracted characters (it can't because "+" isn't a valid number so this step returns an error but step 2 has already happened and isn't undone) The program is behaving "correctly" but I still say it is unintuitive. – Jerry Jeremiah Mar 04 '20 at 22:10
  • So the other commenters are right. Extract the input as a string and then check if it is a string you expect (+, -, *, /, etc) and if it isn't THEN try to convert it to a string with std::stod - that way you know what you are getting. – Jerry Jeremiah Mar 04 '20 at 22:16

1 Answers1

2

The problem

Your programme does not work exactly as intended, because it doesn't take into consideration potentially consumed but lost characters.

Here are different cases that work as expected:

  • abc: the first char read is not numeric, so it's not consumed and cin fails fast. The second reading reads every chars present as a string.
  • 123abc456: the first 123 is read. When a is encountered, it is not consumed since it's not valid numeric. Further reading is stopped, but a numeric value could be read.
  • /123: the first char read is not numeric, so it's not consumed and cin fails. the second reading reads every char present as string.
  • -123 or +123: the first char is considered as a valid numeric char and is read, and then the remainder is read, still as a numeric value. Works as expected if you consider that a double ora an int can be signed. Depending on output formatting, the + might not appear with your output.

Here are the cases that do not work: if the first char is + or - but it is not followed by a valid numeric char. In this case the first char is consumed, but the next char makes the numeric input fail. The remaining chars are then read as string (except the first sign that was already consumed and is lost). Examples:

  • ++123
  • + 123 (the space ends the axtraction of the double that fails, the remainder is read as a string).

Online demo

The solution

The easiest solution is to read the input as a string, then try to convert the string.

For example:

size_t processed;
string hi;
double hello;
cin >> hi;

try {
    hello = stod(hi,&processed); 
    cout<<"number:" <<hello; 
    if (processed<hi.size()) 
        cout << " (followed by something)";
    cout <<endl; 
}
catch (...)   // should be more precise in catching, but it's for the proof of concept 
{
    cout <<"string: "<< hi << endl;
}

Online demo

If you want to consider + and - as alphanumeric, it'd be easy to check if hi is non empty and hi[0] a digit before trying to do the conversion.

Alternatively, you could also do a regex check of the string to see if it matches a numeric format.

Christophe
  • 68,716
  • 7
  • 72
  • 138