Before using the result of cin >> num;
, you should test whether the input conversion was successful or not. One simply way to do this would be to use cin.operator bool
.
std::cout << "Selection> ";
std::cin >> num;
//test for conversion failure
if ( !std::cin )
{
std::cout << "Unable to convert input to integer!\n";
//clear fail flag
std::cin.clear();
//discard remainder of line from input stream
std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );
continue;
}
//input was successful, so we can now use the result
switch ( num )
{
[...]
}
It is important to note that I am discarding the remainder of the line after every attempt to read an integer from the input stream. If I did not do this, then if the user entered k
, then the k
would stay on the input stream, causing the conversion to fail again in the next loop iteration.
Note that you will have to #include <limits>
in order to use std::numeric_limits
.
However, this solution still is not perfect, because if the user enters for example 6k
, then the conversion of the 6
will be successful in the current loop iteration, but it will leave k
on the input stream, so that in the next loop iteration, the program will attempt to convert that k
to an integer, instead of waiting for the user to enter more input. For this reason, it would probably be better to
check the remainder of the line for non-whitespace characters, and treat the entire line as invalid if such a character is found, even if std::cin >> num;
is successful.
discard the remainder of the line in all cases, even in cases in which std::cin >> num;
is successful, and
Here is the full code solution which also fixes the issues mentioned above:
#include <iostream>
#include <limits>
#include <cctype>
int main()
{
for (;;) //infinite loop, equivalent to while(true)
{
int num;
char c;
std::cout <<
"\n"
"---MENU---\n"
"\n"
"1- Insert\n"
"2- remove\n"
"3- SeqSearch\n"
"4- PrintList\n"
"5- Quit\n"
"\n";
std::cout << "Selection> ";
std::cin >> num;
//test for conversion failure
if ( !std::cin )
{
std::cout << "Unable to convert input to integer!\n";
//clear fail flag
std::cin.clear();
//discard remainder of line from input stream
std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );
continue;
}
//verify that remainder of line is either empty or
//contains harmless whitespace characters, and
//discard this remainder
while ( std::cin.get( c ) && c != '\n' )
{
if ( !std::isspace( static_cast<unsigned char>( c ) ) )
{
std::cout << "Invalid character found!\n";
//discard remainder of line
std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );
//we cannot use "continue" here, because that would
//go to the next iteration of the innermost loop, but
//we cant to go the next iteration of the outer loop
goto continue_outer_loop;
}
}
//input was successful, so we can now use the result
switch ( num )
{
case 1:
num = 1;
std::cout << "Insert\n";
break;
case 2:
num = 2;
std::cout << "remove\n";
break;
case 3:
num = 3;
std::cout << "SeqSearch\n";
break;
case 4:
num = 4;
std::cout << "PrintList\n";
break;
case 5:
num = 5;
std::cout << "Exiting the program.\n\n";
return EXIT_SUCCESS;
default:
std::cout << "Invalid Selection\n";
}
continue_outer_loop:
continue;
}
}
Note that this program uses one goto
statement. Normally, goto
should be avoided, but for breaking out of a nested loop, it is acceptable.
This program has the following behavior:
---MENU---
1- Insert
2- remove
3- SeqSearch
4- PrintList
5- Quit
Selection> k
Unable to convert input to integer!
---MENU---
1- Insert
2- remove
3- SeqSearch
4- PrintList
5- Quit
Selection> 6k
Invalid character found!
---MENU---
1- Insert
2- remove
3- SeqSearch
4- PrintList
5- Quit
Selection> 0
Invalid Selection
---MENU---
1- Insert
2- remove
3- SeqSearch
4- PrintList
5- Quit
Selection> 1
Insert
---MENU---
1- Insert
2- remove
3- SeqSearch
4- PrintList
5- Quit
Selection> 2
remove
---MENU---
1- Insert
2- remove
3- SeqSearch
4- PrintList
5- Quit
Selection> 3
SeqSearch
---MENU---
1- Insert
2- remove
3- SeqSearch
4- PrintList
5- Quit
Selection> 4
PrintList
---MENU---
1- Insert
2- remove
3- SeqSearch
4- PrintList
5- Quit
Selection> 5
Exiting the program.