Hello, when I was writing a user-driven test program for a data structure I
wrote, I encountered an annoying problem. The test program is laid out as a
menu with several numbered options. The user selects one option by typing in
its corresponding number (int). Depending on the choice he made, he may be
asked to provide another integer (or no input at all). So all the user does
is entering integers. I don't want the user to be able to cause problems or
crashes by providing invalid input, but he is despite my error checking.
Here follows output from my program here boiled down to a "minimum":
$ ./test
1 - choice one
2 - choice two
3 - exit program
What is your choice? 1
Enter integer to be doubled: 2+2
2 doubled is 4
1 - choice one
2 - choice two
3 - exit program
What is your choice? Enter integer to be squared:
In this test run the user presses 1 when asked for which choice he wants in
the menu. But when asked to input an integer he enters 2+2, and cin does not
go into an error state but leaves the last '2' plus a newline in the stream,
triggering a new menu option (the '+' was eaten by a call to cin.get() which
is supposed to get rid of the newline. Now how can I fix my code so it
doesn't allow this? And why doesn't cin choke on 2+2 when asked to enter an
integer?
#include <iostream>
#include <limits>
#include <string>
int enter_integer(const std::string& prompt);
int main()
{
std::string prompt;
while(true)
{
std::cout << "1 - choice one" << std::endl;
std::cout << "2 - choice two" << std::endl;
std::cout << "3 - exit program" << std::endl;
int n = enter_integer("What is your choice? ");
switch(n)
{
case 1:
n = enter_integer("Enter integer to be doubled: ");
std::cout << n << " doubled is " << n * 2 << std::endl;
break;
case 2:
n = enter_integer("Enter integer to be squared: ");
std::cout << n << " squared is " << n * n << std::endl;
break;
case 3:
return 0;
default:
std::cout << n << " is an invalid menu choice." << std::endl;
}
}
}
int enter_integer(const std::string& prompt)
{
while(true)
{
std::cout << prompt << std::flush;
int n;
std::cin >> n;
if(!std::cin)
{
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsiz e>::max(),
'\n');
std::cout << "You must enter an integer!" << std::endl;
}
else
{
std::cin.get(); /* Get rid of newline in the stream. */
return n;
}
}
return -1; /* Should never be reached. */
}
/ William Payne 10 1960
William Payne wrote: Hello, when I was writing a user-driven test program for a data structure I wrote, I encountered an annoying problem. The test program is laid out as a menu with several numbered options. The user selects one option by typing in its corresponding number (int).
And this is your problem. You read an int.
The simplest thing you can do is to forget the idea of reading an int.
After all, if the user types 2, this is a character just like 'a' or 'b'.
So read everything as character, it simpler then checking the stream for it's
state, getting rid of the invalid input, clearing that error state and thus
make the stream workable again.
Depending on the choice he made, he may be asked to provide another integer (or no input at all).
Having no input at all is tricky when you try to read an int. Again: If you
read in a string, this becomes trivial.
So all the user does is entering integers. I don't want the user to be able to cause problems or crashes by providing invalid input, but he is despite my error checking. Here follows output from my program here boiled down to a "minimum": $ ./test 1 - choice one 2 - choice two 3 - exit program What is your choice? 1 Enter integer to be doubled: 2+2 2 doubled is 4 1 - choice one 2 - choice two 3 - exit program What is your choice? Enter integer to be squared:
In this test run the user presses 1 when asked for which choice he wants in the menu. But when asked to input an integer he enters 2+2, and cin does not go into an error state
why should it?
Streams are defined that they try to read as much as possible to fullfil the
request. The request was to read an int, thus everything that can be an int
is taken from the stream, in your case the first '2'. The rest is left in the
input queue and is waiting for your program to read it.
but leaves the last '2' plus a newline in the stream, triggering a new menu option (the '+' was eaten by a call to cin.get() which is supposed to get rid of the newline. Now how can I fix my code so it doesn't allow this?
look up the ignore() function of the stream.
But again, it's simpler to *not* read the users input as an int. Read it as a string,
then try to extract the number from the string. This way the user can enter whetever
he likes (even no 'numer' at all), and nothing special will happen: The users input
is read as string and your number detection function will not be able to extract
a number from that and thus your program will emit an error. But in no case the
stream has entered a fail state and must be made useable again (for extracting
something from a string, the stringstreams are a handy tool).
And why doesn't cin choke on 2+2 when asked to enter an integer?
See above. It's defined to be that way. If you had entered: '*2' it would
have choked, because '*' is not a valid starting character for an integer.
--
Karl Heinz Buchegger kb******@gascad.at
"William Payne" <mi******************@student.liu.se> wrote... Hello, when I was writing a user-driven test program for a data structure
I wrote, I encountered an annoying problem. The test program is laid out as
a menu with several numbered options. The user selects one option by typing
in its corresponding number (int). Depending on the choice he made, he may be asked to provide another integer (or no input at all). So all the user
does is entering integers. I don't want the user to be able to cause problems
or crashes by providing invalid input, but he is despite my error checking. Here follows output from my program here boiled down to a "minimum": $ ./test 1 - choice one 2 - choice two
Whoever designed this user interface should be shot. Why not write
1 - to double an integer
2 - to square an integer
?
3 - exit program What is your choice? 1 Enter integer to be doubled: 2+2 2 doubled is 4 1 - choice one 2 - choice two 3 - exit program What is your choice? Enter integer to be squared:
In this test run the user presses 1 when asked for which choice he wants
in the menu. But when asked to input an integer he enters 2+2, and cin does
not go into an error state but leaves the last '2' plus a newline in the
stream, triggering a new menu option (the '+' was eaten by a call to cin.get()
which is supposed to get rid of the newline. Now how can I fix my code so it doesn't allow this? And why doesn't cin choke on 2+2 when asked to enter
an integer?
Read the FAQ section 15. 15.2 and 15.3 apply, IMO.
Victor
Karl Heinz Buchegger wrote: William Payne wrote: Hello, when I was writing a user-driven test program for a data structure I wrote, I encountered an annoying problem. The test program is laid out as a menu with several numbered options. The user selects one option by typing in its corresponding number (int). And this is your problem. You read an int. The simplest thing you can do is to forget the idea of reading an int. After all, if the user types 2, this is a character just like 'a' or 'b'. So read everything as character,
Sorry, make that: as string. This also accounts for your user to enter 'abcdefg'
in response to 'Enter a number'.
it simpler then checking the stream for it's state, getting rid of the invalid input, clearing that error state and thus make the stream workable again.
Depending on the choice he made, he may be asked to provide another integer (or no input at all).
Having no input at all is tricky when you try to read an int. Again: If you read in a string, this becomes trivial.
So all the user does is entering integers. I don't want the user to be able to cause problems or crashes by providing invalid input, but he is despite my error checking. Here follows output from my program here boiled down to a "minimum": $ ./test 1 - choice one 2 - choice two 3 - exit program What is your choice? 1 Enter integer to be doubled: 2+2 2 doubled is 4 1 - choice one 2 - choice two 3 - exit program What is your choice? Enter integer to be squared:
In this test run the user presses 1 when asked for which choice he wants in the menu. But when asked to input an integer he enters 2+2, and cin does not go into an error state
why should it? Streams are defined that they try to read as much as possible to fullfil the request. The request was to read an int, thus everything that can be an int is taken from the stream, in your case the first '2'. The rest is left in the input queue and is waiting for your program to read it.
but leaves the last '2' plus a newline in the stream, triggering a new menu option (the '+' was eaten by a call to cin.get() which is supposed to get rid of the newline. Now how can I fix my code so it doesn't allow this?
look up the ignore() function of the stream. But again, it's simpler to *not* read the users input as an int. Read it as a string, then try to extract the number from the string. This way the user can enter whetever he likes (even no 'numer' at all), and nothing special will happen: The users input is read as string and your number detection function will not be able to extract a number from that and thus your program will emit an error. But in no case the stream has entered a fail state and must be made useable again (for extracting something from a string, the stringstreams are a handy tool).
And why doesn't cin choke on 2+2 when asked to enter an integer?
See above. It's defined to be that way. If you had entered: '*2' it would have choked, because '*' is not a valid starting character for an integer.
--
Karl Heinz Buchegger kb******@gascad.at
"Victor Bazarov" <v.********@comAcast.net> wrote in message
news:DofKb.64288$I07.277140@attbi_s53... "William Payne" <mi******************@student.liu.se> wrote...
[snip] 1 - choice one 2 - choice two
Whoever designed this user interface should be shot. Why not write
1 - to double an integer 2 - to square an integer
?
[snip]
LOL, I wrote that and I don't know what I was thinking. The real program has
a menu laid out as you want, though.
[snip]
Read the FAQ section 15. 15.2 and 15.3 apply, IMO.
Victor
I read those sections as you suggested, and I have decided to store the
initial input in a std::string rather than an int and perform error checking
on the string (and converting to int if valid).
Thanks for your reply.
/ William Payne
"Karl Heinz Buchegger" <kb******@gascad.at> wrote in message
news:3F***************@gascad.at... Karl Heinz Buchegger wrote: William Payne wrote: Hello, when I was writing a user-driven test program for a data
structure I wrote, I encountered an annoying problem. The test program is laid out
as a menu with several numbered options. The user selects one option by
typing in its corresponding number (int). And this is your problem. You read an int. The simplest thing you can do is to forget the idea of reading an int. After all, if the user types 2, this is a character just like 'a' or
'b'. So read everything as character,
Sorry, make that: as string. This also accounts for your user to enter
'abcdefg' in response to 'Enter a number'.
it simpler then checking the stream for it's state, getting rid of the invalid input, clearing that error state and
thus make the stream workable again.
Depending on the choice he made, he may be asked to provide another integer (or no input at all).
Having no input at all is tricky when you try to read an int. Again: If
you read in a string, this becomes trivial.
So all the user does is entering integers. I don't want the user to be able to cause
problems or crashes by providing invalid input, but he is despite my error
checking. Here follows output from my program here boiled down to a "minimum": $ ./test 1 - choice one 2 - choice two 3 - exit program What is your choice? 1 Enter integer to be doubled: 2+2 2 doubled is 4 1 - choice one 2 - choice two 3 - exit program What is your choice? Enter integer to be squared:
In this test run the user presses 1 when asked for which choice he
wants in the menu. But when asked to input an integer he enters 2+2, and cin
does not go into an error state
why should it? Streams are defined that they try to read as much as possible to fullfil
the request. The request was to read an int, thus everything that can be an
int is taken from the stream, in your case the first '2'. The rest is left
in the input queue and is waiting for your program to read it.
but leaves the last '2' plus a newline in the stream, triggering a new menu option (the '+' was eaten by a call to cin.get()
which is supposed to get rid of the newline. Now how can I fix my code so it doesn't allow this?
look up the ignore() function of the stream. But again, it's simpler to *not* read the users input as an int. Read it
as a string, then try to extract the number from the string. This way the user can
enter whetever he likes (even no 'numer' at all), and nothing special will happen: The
users input is read as string and your number detection function will not be able to
extract a number from that and thus your program will emit an error. But in no
case the stream has entered a fail state and must be made useable again (for
extracting something from a string, the stringstreams are a handy tool).
And why doesn't cin choke on 2+2 when asked to enter an integer?
See above. It's defined to be that way. If you had entered: '*2' it
would have choked, because '*' is not a valid starting character for an
integer.
-- Karl Heinz Buchegger kb******@gascad.at
Thanks for your reply, Karl. I will do as you suggested and read the user
input into a std::string.
/ William Payne
"William Payne" <mi******************@student.liu.se> wrote in message
news:bt**********@news.island.liu.se... "Karl Heinz Buchegger" <kb******@gascad.at> wrote in message news:3F***************@gascad.at... Karl Heinz Buchegger wrote: William Payne wrote: > > Hello, when I was writing a user-driven test program for a data structure I > wrote, I encountered an annoying problem. The test program is laid
out as a > menu with several numbered options. The user selects one option by typing in > its corresponding number (int).
And this is your problem. You read an int. The simplest thing you can do is to forget the idea of reading an int. After all, if the user types 2, this is a character just like 'a' or 'b'. So read everything as character, Sorry, make that: as string. This also accounts for your user to enter 'abcdefg' in response to 'Enter a number'.
it simpler then checking the stream for it's state, getting rid of the invalid input, clearing that error state and thus make the stream workable again.
> Depending on the choice he made, he may be > asked to provide another integer (or no input at all).
Having no input at all is tricky when you try to read an int. Again:
If you read in a string, this becomes trivial.
> So all the user does > is entering integers. I don't want the user to be able to cause problems or > crashes by providing invalid input, but he is despite my error checking. > Here follows output from my program here boiled down to a "minimum": > $ ./test > 1 - choice one > 2 - choice two > 3 - exit program > What is your choice? 1 > Enter integer to be doubled: 2+2 > 2 doubled is 4 > 1 - choice one > 2 - choice two > 3 - exit program > What is your choice? Enter integer to be squared: > > In this test run the user presses 1 when asked for which choice he wants in > the menu. But when asked to input an integer he enters 2+2, and cin does not > go into an error state
why should it? Streams are defined that they try to read as much as possible to
fullfil the request. The request was to read an int, thus everything that can be
an int is taken from the stream, in your case the first '2'. The rest is left in the input queue and is waiting for your program to read it.
> but leaves the last '2' plus a newline in the stream, > triggering a new menu option (the '+' was eaten by a call to
cin.get() which > is supposed to get rid of the newline. Now how can I fix my code so
it > doesn't allow this?
look up the ignore() function of the stream. But again, it's simpler to *not* read the users input as an int. Read
it as a string, then try to extract the number from the string. This way the user can enter whetever he likes (even no 'numer' at all), and nothing special will happen:
The users input is read as string and your number detection function will not be able
to extract a number from that and thus your program will emit an error. But in no case the stream has entered a fail state and must be made useable again (for extracting something from a string, the stringstreams are a handy tool).
> And why doesn't cin choke on 2+2 when asked to enter an > integer?
See above. It's defined to be that way. If you had entered: '*2' it would have choked, because '*' is not a valid starting character for an integer.
-- Karl Heinz Buchegger kb******@gascad.at
Thanks for your reply, Karl. I will do as you suggested and read the user input into a std::string.
/ William Payne
I have now written a small code snippet that prompts the user to enter an
integer, a snippet which should reject any input that is not a valid
integer. It seems to work but I would like to hear some comments on it if
you please.
int enter_integer(const std::string& prompt)
{
while(true)
{
std::cout << prompt << std::flush;
int n;
std::string input;
/* Maybe use cin.getline() instead and complain if the user *
* enters, for example, 2 2, instead of just silently dis- *
* everything left in stream like we do now? */
std::cin >> input;
std::cin.ignore(std::numeric_limits<std::streamsiz e>::max(),
'\n');
if(!check_if_valid_integer(input))
{
std::cout << input << " is not a valid integer." << std::endl;
}
else
{
std::stringstream ss;
ss << input;
/* check_if_valid_integer() doesn't catch cases where the user just
*
* enters '+' or '-', so we need this check here. Maybe we should
*
* check for that in check_if_valid_integer as well.
*/
if((ss >> n))
{
return n;
}
else
{
std::cout << input << " is not a valid integer." << std::endl;
}
}
}
return -1; /* Should never be reached. Maybe throw exception? */
}
bool check_if_valid_integer(const std::string& s)
{
if(!isdigit(s[0]) && s[0] != '+' && s[0] != '-')
{
return false;
}
return count_if(s.begin() + 1, s.end(), isdigit) == 0;
}
Hope this post doesn't go unnoticed, since I decided to reply to this thread
instead of starting a new one.
/ William Payne
"William Payne" <mi******************@student.liu.se> wrote in message
news:bt**********@news.island.liu.se... Hello, when I was writing a user-driven test program for a data structure
I wrote, I encountered an annoying problem. The test program is laid out as
a menu with several numbered options. The user selects one option by typing
in its corresponding number (int). Depending on the choice he made, he may be asked to provide another integer (or no input at all). So all the user
does is entering integers. I don't want the user to be able to cause problems
or crashes by providing invalid input, but he is despite my error checking. Here follows output from my program here boiled down to a "minimum": $ ./test 1 - choice one 2 - choice two 3 - exit program What is your choice? 1 Enter integer to be doubled: 2+2 2 doubled is 4 1 - choice one 2 - choice two 3 - exit program What is your choice? Enter integer to be squared:
In this test run the user presses 1 when asked for which choice he wants
in the menu. But when asked to input an integer he enters 2+2, and cin does
not go into an error state but leaves the last '2' plus a newline in the
stream, triggering a new menu option (the '+' was eaten by a call to cin.get()
which is supposed to get rid of the newline. Now how can I fix my code so it doesn't allow this? And why doesn't cin choke on 2+2 when asked to enter
an integer?
Other replies have pointed out why it doesn't work but I think you will find
that the right answer is not to use a string or at least
not as in cin >> s.
All programs of this type are line oriented and hence you need to read a
line -
1. use the function getline to read a whole line into a std::string.
2. Make your line the basis of an istringstream, iss
3. read your integer with if( iss >> i)
4. skip whitespace with iss >> std::ws
5. if iss.get() is not now EOF then there was some input you didn't ask for
This does the biz without you explicitly parsing strings and also stops the
user entering extra newlines (remember that all formatted input functions
eat whitespace first and newlines are whitespace).
"William Payne" <mi******************@student.liu.se> wrote in message
news:bt**********@news.island.liu.se...
[Please snip out any text not relevant to your reply, thanks]
| I have now written a small code snippet that prompts the user to enter an
| integer, a snippet which should reject any input that is not a valid
| integer. It seems to work but I would like to hear some comments on it if
| you please.
[snip]
| Hope this post doesn't go unnoticed, since I decided to reply to this thread
| instead of starting a new one.
Oh, it was noticed alright :-).
Having said that, I have modified your code a little:
bool check_if_valid_integer( const std::string& s )
{
static const char* ValidChars( "0123456789" );
return s.find_first_not_of( ValidChars ) == std::string::npos;
}
int enter_integer( const std::string& prompt )
{
while( true )
{
std::cout << prompt << std::flush;
int n;
std::string input;
std::getline( std::cin, input );
if( !check_if_valid_integer( input ) )
{
std::cout << input << " is not a valid integer." << std::endl;
return -1;
// Note: '-1' is a valid integer, it is up to you if you
// want to accept it - throwing an exception may be of
// better here.
}
else
{
std::istringstream ss( input );
if( ss >> n )
return n;
}
}
}
Cheers.
Chris Val
<snip> bool check_if_valid_integer( const std::string& s ) { static const char* ValidChars( "0123456789" );
return s.find_first_not_of( ValidChars ) == std::string::npos; }
wouldn't this be better named check_if_valid_unsigned_integer() ?
To check for valid integer, you need to allow '-' but only in the first postion
no? Why not just use strstream functions?
"Duane Hebert" <sp**@flarn2.com> wrote in message
news:pb*********************@weber.videotron.net.. .
| <snip>
| > bool check_if_valid_integer( const std::string& s )
| > {
| > static const char* ValidChars( "0123456789" );
| >
| > return s.find_first_not_of( ValidChars ) == std::string::npos;
| > }
|
| wouldn't this be better named check_if_valid_unsigned_integer() ?
| To check for valid integer, you need to allow '-' but only in the first postion
| no? Why not just use strstream functions?
Your right(but I didn't want to change it), that's why
I mentioned it, but still allowed it to return a negative
value for the error code.
I should have been a little more clear :-).
Cheers.
Chris Val This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics
by: Chris Mantoulidis |
last post by:
Let's say I have this:
std::string s1;
std::cin >> s1;
This will read s1 from cin until it finds a space (or a newline,
whichever comes first).
Okay this works. But when I want to continue...
|
by: yw |
last post by:
Hi,
When I use std::cin and std::cout to input some data, how can I ingore the
cin by using the Enter key?
For example:
string sname;
cout<<"Please input your name:"<<endl;
cin>>sname;
If...
|
by: puzzlecracker |
last post by:
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
I have seen it in faq - what does it do, exactly?
|
by: moleskyca1 |
last post by:
In C++ FAQ (15.5), I see this code:
int i = 0;
while (std::cin >x) { // RIGHT! (reliable)
++i;
// Work with x ...
}
but I don't know how can while loop end? ostream &operator >>(...)
return...
|
by: junw2000 |
last post by:
Below is simple code:
#include <iostream>
int main(){
int i;
while(1){
while(!(std::cin >i)){
std::cout<<"Invalid input i: "<<i<<'\n';
|
by: Johannes Meng |
last post by:
Good day,
I'm experimenting with unbuffered input at the moment. To get input I
basically use cin.get(). My problem are control sequences preceeded by an
ESC character (i.e. up, down, f-keys et...
|
by: pekka |
last post by:
I'm trying to measure user input time with my Timer class object. It isn't
as easy as I expected. When using std::cin between timer start and stop, I
get zero elapsed time. For some unknown reason,...
|
by: Alex Snast |
last post by:
hello guys
I need to modify the std::cin delim char from the default ' ' and '\n'
characters to ',' i know that i can edit the delim in the getline
command however i'd like to know if there's...
|
by: ryjfgjl |
last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
|
by: emmanuelkatto |
last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud.
Please let me know.
Thanks!
Emmanuel
|
by: Sonnysonu |
last post by:
This is the data of csv file
1 2 3
1 2 3
1 2 3
1 2 3
2 3
2 3
3
the lengths should be different i have to store the data by column-wise with in the specific length.
suppose the i have to...
|
by: Hystou |
last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
|
by: Oralloy |
last post by:
Hello folks,
I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>".
The problem is that using the GNU compilers,...
|
by: jinu1996 |
last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
|
by: Hystou |
last post by:
Overview:
Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
|
by: tracyyun |
last post by:
Dear forum friends,
With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
|
by: agi2029 |
last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
| |