Click to See Complete Forum and Search --> : user input datatype check?


tegwin
September 23rd, 2002, 08:33 PM
hey hey.. can anyone answer this simple question for me?

i have a program that prompts the user to input a number. I then want to check to make sure the user inputs a number and not a character of some kind yet I am unsure of how to do this.

Could someone tell me what i need to do?
I tried the following.

double Distance;
cout << "Enter distance: ";
cin >> Distance;

while(!Distance || Distance < 0)
{
cout << "Error";
cout << "Enter distance: ";
cin >> Distance;
}

the following code works if i enter a negative number.. it will keep prompting me to enter the distance again. But if i type a letter or any other character i get an error at !Distance
any help would be appreciated

cup
September 24th, 2002, 01:27 AM
Instead of !Distance, check for cin.fail ();

tegwin
September 24th, 2002, 09:52 AM
ahh.. thats what i needed.. thnx for the help.. all good now

edit: oop thought was all good but still having problems


double getInput()
{
double Input;
static bool Continue = false;

while (Continue == false)
{
cout << "Input the distance between yourself and the rainbow: ";
cin >> Input;

if (cin.fail() || Input < 0)
{
cout << endl << "Error" << endl;
}
else
{
Continue = true;
}
}
return Input;
}


in the above code:
--if i type a positive number it returns that number.
--if i type a negative number it displays "Error" and re-prompts
user to input another number.
--if i type a character or symbol the program displays "Error"
"Input the distance between yourself and the rainbow: ";
over and over in an infinite loop. It doesn't give the user a
chance to re-enter another number.
I can't figure out why.. any ideas anyone?

cup
September 24th, 2002, 11:13 AM
If it fails, call cin.clear() before you do another input.

Nice message: I've never had that one before. What compiler are you using?

tegwin
September 24th, 2002, 01:05 PM
Using C++ Builder 5 EE as my compiler... BTW where are you getting these function declarations from?!? U know them or are they listed in the visual c++ documentation or you looking through the library files or somethin? I've checked MSDN documentation at microsoft but couldn't locate a list of functions for cin.

Ah crap... just tried it and getting same results.. this is weird and I cannot figure out what the problem is.. i remove the cin.fail() and see what happens when i enter a character.. and i get an invalid point-float variable error.. don't know why a negative number works fine but a character goes into infinite loop.. both inputs should run the exact same code... arggggggg
I guess it could be the compiler... i just don't know anymore..

cup
September 24th, 2002, 01:20 PM
The function declarations are part of ios: it is the abstract stream class. All the stream stuff is derived from ios.

I'll try out your code on VC++ just to see whether I get the same over the rainbow bit.

tegwin
September 24th, 2002, 01:54 PM
i'm confused... i've debugged my program step by step.

If cin.fail() returns true then the next time it comes to cin >> Input;
it just skips right over it.. however if cin.fail() returns false the next time cin>>Input; comes around the program pauses allowing for input thats why negative numbers work fine. i've tried re-ordering the program but nothin' workin'... there wouldn't by any chance be a cin function that would force the program to pause would there?
also when i try cin.clear() it does some weird crap when it comes to cin >> Input the first time around... even though i don't call cin.clear() until later in the program.. :( someone just shoot me now and get it over with....

P.S. very interested on your results with Visual C++

Philip Nicoletti
September 24th, 2002, 02:36 PM
try to ignore() the rest of the line , as ...


double getInput()
{
double Input;
static bool Continue = false;

while (Continue == false)
{
cout << "Input the distance between yourself and the rainbow: ";
cin >> Input;

if (cin.fail() || Input < 0)
{
cout << endl << "Error" << endl;

cin.clear();
cin.ignore(80,'\n'); // ignore rest of line
}
else
{
Continue = true;
}
}
return Input;
}

tegwin
September 24th, 2002, 03:01 PM
Bingo!!! uh.. i mean.. that did that trick... don't know how you thought of that... there must be an easier way to check if user input is correct.... but hey this works.. and thats all that matters... thnx for the help

HeartBreakKid
September 24th, 2002, 03:07 PM
A "Do-While" loop would cut down on a little of the code. Just interjecting because anytime I have ever done user input verification I have used a "Do-While" loop.

Philip Nicoletti
September 24th, 2002, 03:33 PM
A couple of notes :

1) I don't think you want the variable, Continue,
to be static. Currently, it will not input more
than once :


double d1,d2;

d1 = getInput();
d2 = getInput();




2) If the user enters something like 123a, the function
will return 123, and set the input position at the "a", which
will cause an error if getInput() is called a second time.
So you might want to add another ignore() even when successful.


double getInput()
{
double Input;
bool Continue = false;

while (Continue == false)
{
cout << "Input the distance between yourself and the rainbow: ";
cin >> Input;

if (cin.fail() || Input < 0)
{
cout << endl << "Error" << endl;

cin.clear();
cin.ignore(80,'\n'); // ignore rest of line
}
else
{
Continue = true;
}
}
cin.ignore(80,'\n'); // ignore rest of line
return Input;
}

tegwin
September 24th, 2002, 05:19 PM
*ding ding* "Idiot vs Rest of the World" Round 2

yeah i was just noticing what you were talking about. I only call
getInput() once in my program.. but good note for the future with that extra ignore..

I just realized the 123a problem as well and was going to ask if anyone knows how to get around it.. I would like it to return an error if 123a is typed in but like u said it will return 123.
I tried cin.getline() but i don't think it works with double datatypes. I also tried
cin >> value1 >> value2; and tried to do some checking but couldn't find a way to make it work.
Might try using a String with cin.getline() and cast it to a double and then do some kind of checking..
just wanted to know if anyone knows how to avoid 123a problem so i don't spend half an hour trying to find a solution..

AnthonyMai
September 25th, 2002, 08:14 AM
I just realized the 123a problem as well and was going to ask if anyone knows how to get around it.. I would like it to return an error if 123a is typed in but like u said it will return 123.


There is alternative solution. But there is ABSOLUTELY NO CURE as long as your code contains something remotely ressembles:

cin >> myDoubleInput;


Something is fundamentally wrong with the idea of standard stream IO, especially when it is used to read keyboard input. Look at this form of code:


outputFile << str0 << str1 << int2 << obj3 << vector4;
//...
inputFile >> str0 >> str1 >> int2 >> obj3 >> vector4;


The problem is once data of specific type is output, it all concascade into one big chunk of binary bytes with no type information contained in them whatsoever. There is no string, there is no integer, there is no structure, there are only bytes that could be any thing.

So when you read it back in, how do you know what specific data type each byte belongs to? You don't! In the above example, if str0 is "Hello" and str1 is "world", You end up with "Helloworld" in the file, so when you read it back in, should "Helloworld" be read in as one string or two string, or something else?

The >> operator is type casting of the worst category! On the left side of the operator is a stream object which inputs bytes, on the right size it could be any data type. Basically you are trying to cast bytes to any arbitrary data type, no wonder it is error prone.

It's even worse in the case of keyboard input. The user could type trash but the code would presume the data is of expected type, in expected sequence. It would never work, even if the user types correctly. This is an example which would NOT give what you want:

cout << "Please enter your full name" << endl;
cin >> firstName >> middleName >> lastName;


The correct approach, is to treat user input as the data type it is. The user does not enter a double or float, the user does not enter a signed or unsigned 32 bits integer.

All that the user does, is entering a string, followed by a punch on the ENTER key. i.e., the user input should always be read in first as LINES. And then you try to parse lines to exam whether the line contains expected input in expected format. And if it does, then parse the line to get the input. Exactly how you parse the line depends on what the format of the input is, there is no generic way of doing it.

So first you read in the whole line "123a", and parse it as a floating point number one character at a time, and when you done with the parsing, determine if there are additional stuff following it, and there is an "a", so you know it is an error. The code should be pretty easy to write.

Paul McKenzie
September 25th, 2002, 10:33 AM
The problem is once data of specific type is output, it all concascade into one big chunk of binary bytes with no type information contained in them whatsoever. There is no string, there is no integer, there is no structure, there are only bytes that could be any thing.And what does this have to do with iostreams, specifically? Just your chance to rail against iostreams, when there really isn't a reason to do so? This problem exists if you use <stdio.h>So when you read it back in, how do you know what specific data type each byte belongs to? You don't! In the above example, if str0 is "Hello" and str1 is "world", You end up with "Helloworld" in the file, so when you read it back in, should "Helloworld" be read in as one string or two string, or something else?He/she who writes the stream correctly knows how to read the stream correctly. Again, this has nothing specificaly to do with iostreams, the same "problem" exists with <stdio.h>.The >> operator is type casting of the worst category! On the left side of the operator is a stream object which inputs bytes, on the right size it could be any data type. Basically you are trying to cast bytes to any arbitrary data type, no wonder it is error prone.And stdio.h isn't error prone, if not more so?

A database library has a C++ wrapper that overloads << for writing the database object to a file and >> for reading the data base back into the object. Is that a good usage of streams?

If you don't know what input to expect, the solution is as you stated -- read in as a string and parse the data. This has been the solution since the earliest days of computer languages and I/O. The question is what if you do know how to read and write the object correctly, i.e. the input / output is well defined, as in the database library example?

Regards,

Paul McKenzie

TruBic
September 25th, 2002, 04:00 PM
I think we should rename the "123a problem" to Anthony Mai problem :).

TruBic
September 25th, 2002, 04:19 PM
Phillip raise a very good problem, I think. One operation have to be either totally fail or totally success.

In the 123a problem we read part of the input line and think we already read everything from the line. When an error occurs we got confussed like tegwin and try to debug :).

From Phillip 123a problem I got one rule for myself "An operation have to be either totally fail or totally success." That could save us a lot of bug.

Apply to the user input case. I remember in the old day when we have no stream at all, we had to read the input into an buffer and extract data from there(the buffer). That's ensure the input is totally read. In case of error, we can seek back our buffer and see what's wrong, and make decission either to discard or accept the input.

That's just some note. Hopefully it's also worth for your guys.

Philip Nicoletti
September 25th, 2002, 07:01 PM
Concerning your checking algorithm : it is a little
more difficult than that.

For example : -1.0e+20 is a valid double.

Also, what if the user types in : 1.033.334..3 ?

tegwin
September 25th, 2002, 07:21 PM
true dat'
i have no clue how to get around the first double number u posted.. most likely the user won't try and input that and expect it to work... for the decimal problem.. i'm thinkin' about using the find&find_last_of functions...or something like that... and search for a decimal place... if find & find_last_of return a different position then then i know there is more than one decimal and i can return error.... i have fixed everything else and it is all finnally working... thnx for all the help.. hopefully if all goes well this is my last post in this thread

tegwin
September 25th, 2002, 10:26 PM
wow.. i finnally finished.. thnx for the help everyone..
program works perfectly.... I am one happy person..... :D

TruBic
September 26th, 2002, 01:20 PM
Can we have some beer tegwin ? :)