Advanced switch statement within while loop? - c++

I just started C++ but have some prior knowledge to other languages (vb awhile back unfortunately), but have an odd predicament. I disliked using so many IF statements and wanted to use switch/cases as it seemed cleaner, and I wanted to get in the practice.. But..
Lets say I have the following scenario (theorietical code):
while(1) {
//Loop can be conditional or 1, I use it alot, for example in my game
char something;
std::cout << "Enter something\n -->";
std::cin >> something;
//Switch to read "something"
switch(something) {
case 'a':
cout << "You entered A, which is correct";
break;
case 'b':
cout << "...";
break;
}
}
And that's my problem. Lets say I wanted to exit the WHILE loop, It'd require two break statements?
This obviously looks wrong:
case 'a':
cout << "You entered A, which is correct";
break;
break;
So can I only do an IF statement on the 'a' to use break;? Am I missing something really simple?
This would solve a lot of my problems that I have right now.

I would refactor the check into another function.
bool is_correct_answer(char input)
{
switch(input)
{
case 'a':
cout << "You entered A, which is correct";
return true;
case 'b':
cout << "...";
return false;
}
return false;
}
int main()
{
char input;
do
{
std::cout << "Enter something\n -->";
std::cin >> input;
} while (!is_correct_answer(input));
}

You could simply have the while loop check for a bool value that is set within one of your case statements.
bool done = false;
while(!done)
{
char something;
std::cout << "Enter something\n -->";
std::cin >> something;
//Switch to read "something"
switch(something) {
case 'a':
cout << "You entered A, which is correct";
done = true; // exit condition here
break;
case 'b':
cout << "...";
break;
}
}

Yes, C and C++ have no way to say "exit multiple breakable blocks" (where a "breakable block" is any loop or switch). Workarounds include gotos and use of boolean variables to record whether an outer "breakable block" should also break (neither is elegant, but, that's life).

Two break statements will not get you out of the while loop. The first break only gets you out of the switch statement and the second one is never reached.
What you need is to make the condition of the while loop false, assuming that there is nothing in the loop after the switch statement. If there is other code after the switch, you should check the condition after the switch, and break there.
bool done = false;
while(! done)
{
// do stuff
switch(something)
{
case 'a':
done = true; // exit the loop
break;
}
// do this if you have other code besides the switch
if(done)
break; // gets you out of the while loop
// do whatever needs to be done after the switch
}

You could try:
Using Flags
Using Goto
Having the Inner Breakable block into a function
Using Exceptions
Using longjump and setjmp
A topic very similar to this question
http://www.gamedev.net/community/forums/topic.asp?topic_id=385116

You might be interested in the named loop idiom in C++.
#define named(blockname) goto blockname; \
blockname##_skip: if (0) \
blockname:
#define break(blockname) goto blockname##_skip;
named(outer)
while(1) {
//Loop can be conditional or 1, I use it alot, for example in my game
char something;
std::cout << "Enter something\n -->";
std::cin >> something;
//Switch to read "something"
switch(something) {
case 'a':
cout << "You entered A, which is correct";
break(outer);
case 'b':
cout << "...";
break(outer);
}
}

You can also encapsulate the loop into a function and call return inside the case, for the case that the flag breaking the while is not enough.
It is not a good programming practice for some people but if you keep the function simple I don't see why not.

You could replace the switch with a slightly over-engineered OO solution...
#include <iostream>
#include <map>
#include <set>
class input_responder
{
std::set<char> correct_inputs;
std::map<char, const char*> wrong_inputs;
public:
input_responder()
{
correct_inputs.insert('a');
wrong_inputs['b'] = "...";
}
bool respond(char input) const
{
if (correct_inputs.find(input) != correct_inputs.end())
{
std::cout << "You entered " << input << ", which is correct\n";
return true;
}
else
{
std::map<char, const char*>::const_iterator it = wrong_inputs.find(input);
if (it != wrong_inputs.end())
{
std::cout << it->second << '\n';
}
else
{
std::cout << "You entered " << input << ", which is wrong\n";
}
return false;
}
}
};
int main()
{
const input_responder responder;
char input;
do
{
std::cout << "Enter something\n -->";
std::cin >> input;
} while (responder.respond(input) == false);
}

You could change your switch to an ifsystem. It will be compiled to the same thing anyway.

Related

C++: Telling user to input A, B, or C but what if they enter a different character?

As the title suggests, I have a working program for when a user inputs A B or C. My professor has said that we have not gone over repetition yet so we just need to put in a line of code that returns something like "Please enter either A B or C" when the user enters any other character but I am having trouble figuring out how to do this. Any help will be very appreciated. I'll post a file of the code I have now.
https://docs.google.com/document/d/1EVxLPtOsBbdmCCt0LwUDYkqgySg8bSm3w_d_CAcGW6g/edit?usp=sharing
Here is a common stencil for processing menus:
bool invalid_selection = true;
while (invalid_selection)
{
// Output the menu with choices
// ...
char choice;
std::cin >> choice;
choice = std::toupper(choice);
switch (choice)
{
case 'A':
do_something;
break;
// ... other choices ...
default:
std::cout << "Invalid choice.";
}
if (choice == quit_character)
{
break; // exit out of the loop
}
}
There are many other alternatives. For example, one is a do-while loop.
If you don't know about switch, use your if-else-if ladder. The final else clause is equivalent to the default case.
EDIT: It'd be even better to use a std::string as a buffer to prevent receiving multiple errors from this if the user inputs more than one char.
The best way to handle this would probably be a simple do... while nested switch statement:
#include <string>
bool repeat = true;
do {
std::string buffer;
cout << "Which plan do you want to use?" << endl;
cin >> buffer;
// check if the user entered only one character
if (buffer.length() > 1) {
cout << "Invalid Input" << endl;
continue;
}
plan = buffer[0];
switch(plan) {
case 'A':
// do things
repeat = false;
break;
case 'B':
// do things
repeat = false;
break;
case 'C':
// do things
repeat = false;
break;
default:
cout << "Invalid input, please try again." << endl;
break;
} while (repeat);
This keeps asking the user for which plan they want to use, until you receive valid input.
Note: OP did not want a complete refactoring of his code. So this is the minimal-intervention solution.
Edit your if statements to:
if(plan=='A'){
//...
} else if(plan=='B'){
//...
} else if(plan=='C'){
//...
} else {
//handle the error here.
cout << "Wrong input" << endl;
}

c++ avoiding boolean flag to leave loop while using return 0

I have a do while loop which consists of two switch statements, some output code and some nested while loops to check for input errors. The thing is I want to break the switch statement when the user inputs 'Q' for quit and skip the rest of the code. So I've essentially got two problems.
If i use a do while, then it turns into being a return 0 and a boolean flag while(true) which logically goes against itself.
if i drop the do while and only use return 0, the code can't be executed multiple times.
I've come to terms with this being a flow problem rather than a syntax problem and was wondering how I should structure the flow to make it "clean code".
A quick example:
do {
char answer;
cout << "Type answer: ";
cin >> answer;
switch (answer) {
case A:
cout << "hello";
break;
case B:
cout << "more weird output";
break;
case Q:
cout << "Goodbye";
return 0;
}
cout << "more useless output that I want to skip";
cout << "how does this even work";
} while (run);
Here I've a return 0 which completely negates the need for a while(run) flag. This is bad coding practice I've been told, so I was wondering how one would go about structuring this in a good manner?
Here I think i fixed the code. Make sure you are typing a capital Q not lowercase. Also you forgot ' ' around your chars. Your logic was right - just small errors :) Goodluck!
#include <iostream>
using namespace std;
int
main ()
{
bool run = true;
do
{
char answer;
cout << "Type answer: ";
cin >> answer;
switch (answer)
{
case 'A':
cout << "hello";
break;
case 'B':
cout << "more weird output";
break;
case 'Q':
cout << "Goodbye";
return 0;
}
cout << "more useless output that I want to skip";
cout << "how does this even work";
}while (run);
return 0;
}

I need to user an enumerations to represent difficulties levels. I keep getting an error about using cin>>

I have to use a enumerations to represent the difficulty levels. Here is the code.
// Menu Chooser
// Demonstrates the switch statement
#include <iostream>
#include <string>
using namespace std;
int main()
{
cout << "Difficulty Levels\n\n";
cout << "1 - Easy\n";
cout << "2 - Normal\n";
cout << "3 - Hard\n\n";
enum userChoice {Easy, Normal, Hard};
userChoice choice;
cout << "Choice: ";
cin >> choice;
switch (choice)
{
case 1:
cout << "You picked Easy.\n";
break;
case 2:
cout << "You picked Normal.\n";
break;
case 3:
cout << "You picked Hard.\n";
break;
default:
cout << "You made an illegal choice.\n";
}
return 0;
}
and the error message:
error C2678: binary '>>' : no operator found which takes a left-hand
operand of type 'std::istream' (or there is no acceptable conversion)
There is no default implementation of the >> operator for taking an input and mapping it to an enum. You will need to take in an int as an input and then map it to the enum. Alternatively, you could write an overload for the >> operator that maps the input to your enum.
Of course, looking at your code, you don't seem to be using the defined enum for anything. Perhaps you could remove it and use an int instead?
You need to place your enum values into your cases:
switch (choice)
{
case Easy:
cout << "You picked Easy.\n";
break;
case Normal:
cout << "You picked Normal.\n";
break;
case Hard:
cout << "You picked Hard.\n";
break;
default:
cout << "You made an illegal choice.\n";
}
To convert from text to enum type, I suggest you use a table (your instructor probably hasn't covered the topic of std::map which would be the preferred method).
struct Enum_Entry
{
UserChoice value;
const char * text;
};
static const Enum_Entry lookup_table[] =
{
{Easy, "easy"},
{Normal, "normal"},
{Hard, "hard"},
};
static const unsigned int items_in_table =
sizeof(lookup_table) / sizeof(lookup_table[0]);
std::string selection_text;
// Input enum as text
std::cin >> selection_text;
// Convert to lower case to make comparison easier
std::transform(selection_text.begin(), // Start of range
selection_text.end(), // End of range
selection.begin(), // Destination for transformation.
std::tolower); // Transformation function.
// Lookup the text into the table and retrieve the enum value.
UserChoice choice = Easy;
for (unsigned int i = 0; i < items_in_table; ++i)
{
if (selection_text == lookup_table[i].text)
{
choice = lookup_table[i].value;
break;
}
}
Another method is to use an if-else-if ladder:
choice = easy;
if (selection_text == "easy")
{
choice = Easy;
}
else if (selection_text == "hard")
{
choice = Hard;
}
else if (selection_text == "normal")
{
choice = Normal;
}
else
{
choice = Easy;
}
When reading user input, it is not safe to expect they will enter a correct value. However, this seems extreme for your assignment.
My first thought is to just read in an int, then cast it to the enum.
int input;
cin >> input;
userChoice choice = (userChoice)input;
This should work, however I haven't tested it.

How to prevent the user from entering more than one character in the below sample code?

I am facing problem in the below code. If the user enter more than one charater then my loop gets executed number of times equal to the length of the string entered by the user. My code is written in GNU c/c++ compiler.
Thanks in advance.
int continue_option()
{
char c;
loop:
fflush(stdin);
cin.ignore();
cout<<"\n\n\t\t\t\tPress (Y/y) - Continue / Press (N/n) - Exit :";
cin>>c;
if(c=='y'||c=='Y')
{
system("clear");
}
else if(c=='n'|| c=='N')
{
exit(0);
}
else
{
printf("\n\t\t\t\tInvalid Option.Try Again.....");
goto loop;
}
fflush(stdin);
}
First thing, don't use jumps. They are old style, and they make Dijkstra spin in his grave, on top of all the other bad consequences. I don't mean "vintage", I really mean old in the bad sense.
As of your question, I'd rather put the result in a std::string and only consider the first character in there:
std::string input;
std::cin >> input;
switch (input[0]) {
case 'y':
case 'Y':
//your code
break;
case 'n':
case 'N':
exit(0);
default:
std::cout << "Invalid text" << std::endl;
}
I would also refrain from using exit(), I'd rather rely on a function's return value to finally cause a return 0; in the main(), or some equivalent technique.
You can't stop the user from typing more than one character.
What you can do is ignore the rest of the line. You have already use cin.ignore() which ignores one character. You can use cin.ignore(large number) to ignore up to the large number or the end-of-line, whichever appears first.
Unlike flushing output files, fflush(stdin) doesn't really do anything.
Try using cin.get() or getch() to read just one character at a time. Also, I guess you'd be better off replacing the whole thing with a simple loop like:
char ch = '\0';
do
{
ch = getch();
}while((tolower(ch) != 'y') || (tolower(ch) != 'n'))
if(tolower(ch) == 'y')
{
//additional handling
}
else
{
exit(0);
}
Not exactly the same behavior, but should put you on track:
#include <iostream>
#include <iomanip>
bool is_valid_answer(char c)
{
switch(c)
{
case 'y':
case 'Y':
case 'n':
case 'N':
return true;
default:
return false;
}
}
bool continue_option()
{
std::cout << "Press (Y/y) to continue, (N/n) to exit: " << std::flush;
char c = '\0';
while (std::cin.get(c) && !is_valid_answer(c));
return ((c == 'y') || (c == 'Y'));
}
int main()
{
std::cout << "Continue option: " << continue_option() << std::endl;
}

How do I use an enum value in a switch statement in C++?

I would like to use an enum value for a switch statement. Is it possible to use the enum values enclosed in "{}" as choices for the switch()"?
I know that switch() needs an integer value in order to direct the flow of programming to the appropriate case number. If this is the case, do I just make a variable for each constant in the enum statement?
I also want the user to be able to pick the choice and pass that choice to the switch() statement.
For example:
cout << "1 - Easy, ";
cout << "2 - Medium, ";
cout << "3 - Hard: ";
enum myChoice { EASY = 1, MEDIUM = 2, HARD = 3 };
cin >> ????
switch(????)
{
case 1/EASY: // (can I just type case EASY?)
cout << "You picked easy!";
break;
case 2/MEDIUM:
cout << "You picked medium!";
break;
case 3/HARD: // ..... (the same thing as case 2 except on hard.)
default:
return 0;
}
You can use an enumerated value just like an integer:
myChoice c;
...
switch( c ) {
case EASY:
DoStuff();
break;
case MEDIUM:
...
}
You're on the right track. You may read the user input into an integer and switch on that:
enum Choice
{
EASY = 1,
MEDIUM = 2,
HARD = 3
};
int i = -1;
// ...<present the user with a menu>...
cin >> i;
switch(i)
{
case EASY:
cout << "Easy\n";
break;
case MEDIUM:
cout << "Medium\n";
break;
case HARD:
cout << "Hard\n";
break;
default:
cout << "Invalid Selection\n";
break;
}
Some things to note:
You should always declare your enum inside a namespace as enums are not proper namespaces and you will be tempted to use them like one.
Always have a break at the end of each switch clause execution will continue downwards to the end otherwise.
Always include the default: case in your switch.
Use variables of enum type to hold enum values for clarity.
see here for a discussion of the correct use of enums in C++.
This is what you want to do.
namespace choices
{
enum myChoice
{
EASY = 1 ,
MEDIUM = 2,
HARD = 3
};
}
int main(int c, char** argv)
{
choices::myChoice enumVar;
cin >> enumVar;
switch (enumVar)
{
case choices::EASY:
{
// do stuff
break;
}
case choices::MEDIUM:
{
// do stuff
break;
}
default:
{
// is likely to be an error
}
};
}
You can use a std::map to map the input to your enum:
#include <iostream>
#include <string>
#include <map>
using namespace std;
enum level {easy, medium, hard};
map<string, level> levels;
void register_levels()
{
levels["easy"] = easy;
levels["medium"] = medium;
levels["hard"] = hard;
}
int main()
{
register_levels();
string input;
cin >> input;
switch( levels[input] )
{
case easy:
cout << "easy!"; break;
case medium:
cout << "medium!"; break;
case hard:
cout << "hard!"; break;
}
}
I had a similar issue using enum with switch cases.
Later, I resolved it on my own....below is the corrected code, and perhaps this might help.
//Menu Chooser Programme using enum
#include <iostream>
using namespace std;
int main()
{
enum level{Novice=1, Easy, Medium, Hard};
level diffLevel = Novice;
int i;
cout << "\nEnter a level: ";
cin >> i;
switch(i)
{
case Novice:
cout << "\nyou picked Novice\n"; break;
case Easy:
cout << "\nyou picked Easy\n"; break;
case Medium:
cout << "\nyou picked Medium\n"; break;
case Hard:
cout << "\nyou picked Hard\n"; break;
default:
cout << "\nwrong input!!!\n"; break;
}
return 0;
}
You should keep in mind that if you are accessing a class-wide enum from another function, even if it is a friend, you need to provide values with a class name:
class PlayingCard
{
private:
enum Suit { CLUBS, DIAMONDS, HEARTS, SPADES };
int rank;
Suit suit;
friend std::ostream& operator<< (std::ostream& os, const PlayingCard &pc);
};
std::ostream& operator<< (std::ostream& os, const PlayingCard &pc)
{
// Output the rank ...
switch(pc.suit)
{
case PlayingCard::HEARTS:
os << 'h';
break;
case PlayingCard::DIAMONDS:
os << 'd';
break;
case PlayingCard::CLUBS:
os << 'c';
break;
case PlayingCard::SPADES:
os << 's';
break;
}
return os;
}
Note how it is PlayingCard::HEARTS and not just HEARTS.
The user's input will always be given to you in the form of a string of characters... if you want to convert the user's input from a string to an integer, you'll need to supply the code to do that. If the user types in a number (e.g. "1"), you can pass the string to atoi() to get the integer corresponding to the string. If the user types in an english string (e.g. "EASY") then you'll need to check for that string (e.g. with strcmp()) and assign the appropriate integer value to your variable based on which check matches. Once you have an integer value that was derived from the user's input string, you can pass it into the switch() statement as usual.
#include <iostream>
using namespace std;
int main() {
enum level {EASY = 1, NORMAL, HARD};
// Present menu
int choice;
cout << "Choose your level:\n\n";
cout << "1 - Easy.\n";
cout << "2 - Normal.\n";
cout << "3 - Hard.\n\n";
cout << "Choice --> ";
cin >> choice;
cout << endl;
switch (choice) {
case EASY:
cout << "You chose Easy.\n";
break;
case NORMAL:
cout << "You chose Normal.\n";
break;
case HARD:
cout << "You chose Hard.\n";
break;
default:
cout << "Invalid choice.\n";
}
return 0;
}
You can cast enum with int.
enum TYPE { one, two, tree };
TYPE u;
u = two;
switch( int( u ) ){
case one :
action = do_something ;
break;
case two:
action = do_something_else;
break;
}