Jump to content
  • Advertisement
Sign in to follow this  
BUnzaga

How to check for input 'type' ?

This topic is 4169 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello, I am doing several tutorials where I do something like:
#include <iostream>
using namespace std;

int i1;//I just named these i1 and i2 for interger1 and 2
int i2;

int main()
{
    cout<<"Enter an interger: "<<endl;
    cin>>i1;
    cout<<"Enter another interger: "<<endl;
    cin>>i2;
    cout<<i1<<" + "<<i2<<" = "<<i1+i2<<endl;
    return 0;
}
Ok so if I enter a char or float for these two values i1 and i2, the code just skips to the end and says to press any key to continue. So how would I do a 'type check' or a pre-error check, so if they didn't enter an int the program would cycle back and request another number. I know I would use an if or while statement, but what is the expression I would use?
do
{
cout<<"Enter an interger: "<<endl;
cin>>i1;
}
while (i1!=int)
Something like that...

Share this post


Link to post
Share on other sites
Advertisement
The use of cin with >> when data is in the buffer that is not of the type requested sets 'cin's fail bit, which makes cin completely unusable until the error is dealt with, which is why the program burns straight through to the end when you enter words. Every cin call returns immediately, and does not fill the i1 or i2 with anything at all [does not change the value of the variable].

You can call cin.fail() [which returns true if the value is bad] to test for these errors, and cin.clear() to return cin to a usable state [so it will actually work again]. This failure mechanism means that there is no way that you can get cin dig through the provided data for something useful, thus doing type checking for you in the manner you describe. You CAN do a version of type checking, by reading in various data types [and failing], until you get one that succeeds [do a string last though, since a string can suck up numbers too]

The this approach is demonstrated here.


int main()
{
int anInteger;
float aFloat;
string garbage;
bool aNumberWasGotten = false;
while(aNumberWasGotten == false)
{
cin >> anInteger;
if(cin.fail())
{
cin.clear();
cin >> aFloat;
if(!cin.fail())
{
cout << "Enter an INTEGER!, not a float!" << endl;
}
else// float failed
{
cin.clear();
cin >> garbage;
cout << "Enter an INTEGER!, not this... whatever '" << garbage << "' is..." << endl;
}
}
else
{
aNumberWasGotten = true;
}
}
cout << "you entered an integer!, yay!" << endl;
return 0;
}





Error checking is always nasty, but when you have the possibility of bad data, it needs to be done.

Share this post


Link to post
Share on other sites
Best way I know is to read a line into a std::string then use a stringstream to convert the string into an int. That way you can check the error state of the stringstream after the conversion:


#include <string>
#include <sstream>
#include <iostream>

int main()
{
std::string s;

std::cout << "Enter an int: ";
std::getline(std::cin,s);

std::istringstream is(s);
int i;

is >> i;

if(is.fail()) std::cout << "You do not have an int!\n";
}


It is also worth checking that the stringstream is empty of anything but whitespace after the conversion since if you enter, say, 23.54, the stringstream will put 23 into the int and leave .54 in the stream ready for the next extraction.

I think I check it is empty by doing >> to a std::string and making sure that the stringstream DOES fail.

Share this post


Link to post
Share on other sites
You can evaluate the stream in a boolean context to determine if it is in a valid state. Note that a failed read places the string in an invalid state. The typical reading code looks like this.


if (std::cin >> i1) { /* Success */ } else { /* Failure */ }


On success, the key is to determine why the reading failed. There are two possible explanations: the data inside the stream was invalid (you entered a non-integer), at which point you may ignore the first few characters, restore the state of the string to a valid one using std::cin.clear(), and read again.

The other explanation is that the end of the stream was reached, in which case std::cin.eof() returns true. You should then handle the fact that no more input will be received.

Share this post


Link to post
Share on other sites
Ok, so why isn't this working?


//bool gotI1=false, using std, included iostream

while(!gotI1)
{
cout<<"Enter an interger: "<<endl;
if(cin>>i1)
{
gotI1=true;
}
else
{
cin.clear();
}
}




I want it to run through once, see if the value in cin returns 'true', if not clear cin and cycle back through.

The problem is that when I enter a char or float, it just keeps failing cin every loop, so it just spams 'Enter an interger: ".

What am I missing?

Keep in mind, I am just doing this to understand error checking, It's not for an assignment or a program. Most of the stuff I will be doing in the future will deal with a user interface and stuff, so I hope error checking won't be such an issues, but I figured I should get used to how it works.

[edit]I guess I have to clear the value stored in i1 ?[/edit]

Share this post


Link to post
Share on other sites
Your code attempts to read data into an integer. If it fails, it tries again with the exact same stream, which obviously will fail again. This is because neither failure nor clear will alter the data inside the stream.

Once the stream reaches an invalid state, you have to do something about the data it contains, such as removing the first character (which would be invalid), before trying the same reading attempt again.

Share this post


Link to post
Share on other sites
I am not sure how to do something like that yet. I can just move on and keep reading my tutorial, but if it's a simple command or something could you post an example?

In the javascript code I have been using, I would use something like i1=null. Is there something like that in C++?

Share this post


Link to post
Share on other sites
Quote:
Original post by BUnzaga
In the javascript code I have been using, I would use something like i1=null. Is there something like that in C++?


The stream doesn't care about i1. If reading fails, i1 has not even been modified. The problem here is about the stream contents, not the integer.

Suppose you enter the text "Hello" at the prompt. So, the beginning of standard input is "Hello". Then, std::cin >> i1 attempts to read "Hello" as an integer. It fails, because "Hello" is not a valid integer, which places std::cin in an invalid state, leaves "Hello" in the stream, and does not modify the integer.

Your code then calls std::cin.clear() to notify std::cin that you are aware of the error. Note that the beginning of standard input is still "Hello", as no successful read operation has been performed so far. Then, your loop repeats, and you try to perform std::cin >> i1 again. Note that the contents or the input stream are still "Hello", because you have not done anything with the stream to change its contents, so the reading of "Hello" as an integer fails again.

Your code then calls std::cin.clear() again to notify std::cin that you are aware of the new error. Again, note that the beginning of standard input is still "Hello", as you have still not managed to perform a succesful read operation on your stream. Your loop repeats once more, and the code executes std::cin >> i1 for a third time. The input stream still starts with "Hello", because its contents have still not been altered by a successful read, so reading it as an integer fails once more.

This cycle repeats on and on, without any reason to stop. Basically, your program reaches the situation "the stream contains invalid data", to which you respond "do not worry, try again", where a sane answer would be "do not worry, remove the invalid data, then try again".

Share this post


Link to post
Share on other sites
Ahh, it makes sense now. So what is the command to erase the information stored in cin? This way when the program loops, it can get fresh information to work with?

I'll look in the help files and see if I can find something, but I just thought I'd ask in case anyone knew off the top of thier heads.

[edit]
Ok so this is what I got, but I'm getting some other error when trying to build it.

#include <iostream>
using namespace std;

int i1;//I just named these i1 and i2 for interger1 and 2
int i2;
string s1;
float f1;

bool gotI1=false;
bool gotI2=false;

int main()
{
while(!gotI1)
{
cout<<"Enter an interger: "<<endl;
if(cin>>i1)
{
gotI1=true;
}
else
{
cin.clear();
if(cin>>f1)
{
cout<<"Enter an interger, not a float!"<<endl;
}
else
{
cin.clear();
if(cin>>s1)
{
cout<<"Enter an interger, not a string!"<<endl;
}
}
}
}
/* cout<<"Enter another interger: "<<endl;
cin>>i2;
cout<<i1<<" + "<<i2<<" = "<<i1+i2<<endl;
*/

return 0;
}



The error I get is:

error C2679: binary '>>' : no operator found which takes a right-hand operand of type 'std::string' (or there is no acceptable conversion)

I'm looking that error up now.

[edit-2]
Ok so I had to use #include<string> I am really new, so I didn't know.

It seems to be working well now, except if I enter a float, it just skips to the end, if I enter a string or character it cycles through as it should, if I enter an int, it works right, but if I enter a floating number it just acts as though the if statements aren't there.

[Edited by - BUnzaga on April 21, 2007 4:12:36 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by BUnzaga
It seems to be working well now, except if I enter a float, it just skips to the end, if I enter a string or character it cycles through as it should, if I enter an int, it works right, but if I enter a floating number it just acts as though the if statements aren't there.


It depends on what float you are attempting to read. Try '.25' and it will read it as a float, and fail the integer test. Try '12.25' and it'll suck up '12' as an int, and leave '.25' in the bit stream [to cause you a headache later], thus succeeding in the int read, and not triggering your error checking.

These sorts of things are exactly why dealing with user input is such a pain.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!