"William Payne" <mikas493_no_s_p_a_m_@student.liu.se> wrote in message
news:btc27v$ee9$1@news.island.liu.se...[color=blue]
>
> "Karl Heinz Buchegger" <kbuchegg@gascad.at> wrote in message
> news:3FF98308.5B632C25@gascad.at...[color=green]
> > Karl Heinz Buchegger wrote:[color=darkred]
> > >
> > > William Payne wrote:
> > > >
> > > > Hello, when I was writing a user-driven test program for a data[/color][/color]
> structure I[color=green][color=darkred]
> > > > wrote, I encountered an annoying problem. The test program is laid[/color][/color][/color]
out[color=blue]
> as a[color=green][color=darkred]
> > > > menu with several numbered options. The user selects one option by[/color][/color]
> typing in[color=green][color=darkred]
> > > > 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[/color][/color]
> 'b'.[color=green][color=darkred]
> > > So read everything as character,[/color]
> >
> > Sorry, make that: as string. This also accounts for your user to enter[/color]
> 'abcdefg'[color=green]
> > in response to 'Enter a number'.
> >[color=darkred]
> > > it simpler then checking the stream for it's
> > > state, getting rid of the invalid input, clearing that error state and[/color][/color]
> thus[color=green][color=darkred]
> > > 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:[/color][/color][/color]
If[color=blue]
> you[color=green][color=darkred]
> > > 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[/color][/color]
> problems or[color=green][color=darkred]
> > > > crashes by providing invalid input, but he is despite my error[/color][/color]
> checking.[color=green][color=darkred]
> > > > 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[/color][/color]
> wants in[color=green][color=darkred]
> > > > the menu. But when asked to input an integer he enters 2+2, and cin[/color][/color]
> does not[color=green][color=darkred]
> > > > go into an error state
> > >
> > > why should it?
> > > Streams are defined that they try to read as much as possible to[/color][/color][/color]
fullfil[color=blue]
> the[color=green][color=darkred]
> > > request. The request was to read an int, thus everything that can be[/color][/color][/color]
an[color=blue]
> int[color=green][color=darkred]
> > > is taken from the stream, in your case the first '2'. The rest is left[/color][/color]
> in the[color=green][color=darkred]
> > > 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[/color][/color][/color]
cin.get()[color=blue]
> which[color=green][color=darkred]
> > > > is supposed to get rid of the newline. Now how can I fix my code so[/color][/color][/color]
it[color=blue][color=green][color=darkred]
> > > > 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[/color][/color][/color]
it[color=blue]
> as a string,[color=green][color=darkred]
> > > then try to extract the number from the string. This way the user can[/color][/color]
> enter whetever[color=green][color=darkred]
> > > he likes (even no 'numer' at all), and nothing special will happen:[/color][/color][/color]
The[color=blue]
> users input[color=green][color=darkred]
> > > is read as string and your number detection function will not be able[/color][/color][/color]
to[color=blue]
> extract[color=green][color=darkred]
> > > a number from that and thus your program will emit an error. But in no[/color][/color]
> case the[color=green][color=darkred]
> > > stream has entered a fail state and must be made useable again (for[/color][/color]
> extracting[color=green][color=darkred]
> > > 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[/color][/color]
> would[color=green][color=darkred]
> > > have choked, because '*' is not a valid starting character for an[/color][/color]
> integer.[color=green][color=darkred]
> > >[/color]
> >
> > --
> > Karl Heinz Buchegger
> >
kbuchegg@gascad.at[/color]
>
> Thanks for your reply, Karl. I will do as you suggested and read the user
> input into a std::string.
>
> / William Payne
>
>[/color]
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