Navigating console menu - c++

I'm totally new and I don't know how else to ask this or what to even search for.
The case is this: I want to navigate through a menu with several sub-menus. In this example I'll just use "options" and a "game" to illustrate what I mean. Say you have a menu with 3 options.
1 - Start
2 - Options
3 - Quit
Choosing options should take you to another menu. Which would then look something like
1 - Difficulty
2 - Sound
3 - Back
Depending on where you go from here, there will be more sub menus obviously.
I've tried nesting do-while loops and all kinds of things but I just don't have enough understanding to know what it is I'm doing wrong.
Here is what I have so far:
#include <cstdlib>
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
int choice;
do{
cout << "Main Menu\n";
cout << "Please make your selection\n";
cout << "1 - Start game\n";
cout << "2 - Options\n";
cout << "3 - Quit\n";
cout << "Selection: ";
cin >> choice;
switch(choice) {
case 1:
cout << "Pew pew!\n";
break;
case 2:
cout <<"????\n";
break;
case 3:
cout << "Goodbye!";
break;
default:
cout << "Main Menu\n";
cout << "Please make your selection\n";
cout << "1 - Start game\n";
cout << "2 - Options\n";
cout << "3 - Quit\n";
cout << "Selection: ";
cin >> choice;
}
} while(choice !=3);
system("PAUSE");
return EXIT_SUCCESS;
}
Which works like a regular menu. But I have no idea where to go from here. I consulted some books, but finding anything even remotely related to this was completely random. Any help or examples would be greatly appreciated.
What happened with nesting tons of loops just made all loops execute simultaneously every time. How do I keep this from happening? Making more choices? (choice1-2-3 etc ? or what?)

Ok guys. Thanks for all the help. This is what I ended up with in the end.
It runs as I want it to and by max_'s example and Mike B's commentary I think this works pretty well.
Thanks alot everyone =)
#include <iostream>
#include <cstdlib>
using namespace std;
void menu();
void mainMenu();
void optionsMenu();
void options();
int choice1 = 0;
int choice2 = 3;
int main(int argc, char** argv) {
menu();
return 0;
}
void menu(){
do {
choice2 = 0;
mainMenu();
switch(choice1) {
case 1:
cout << "Pew pew!\n";
break;
case 2:
options();
break;
case 3:
break;
}
} while(choice1 != 3);
}
void options(void) {
do {
optionsMenu();
switch(choice2){
case 1:
cout << "So difficult!\n";
break;
case 2:
cout << "Beep!\n";
break;
case 3:
break;
default:
break;
}
} while(choice2 != 3);
}
void mainMenu(void) {
cout << "Main Menu\n";
cout << "1 - Start game\n";
cout << "2 - Options\n";
cout << "3 - Quit\n";
cout << "Please choose: ";
cin >> choice1;
}
void optionsMenu(void) {
cout << "Options Menu\n";
cout << "1 - Difficulty\n";
cout << "2 - Sound";
cout << "3 - Back\n";
cout << "Please choose: ";
cin >> choice2;
}

How about this (dunno if it compiles though):
#include <cstdlib>
#include <iostream>
using namespace std;
int GetInput()
{
int choice;
cin >> choice;
return choice;
}
void DisplayMainMenu()
{
cout << "Main Menu\n";
cout << "Please make your selection\n";
cout << "1 - Start game\n";
cout << "2 - Options\n";
cout << "3 - Quit\n";
cout << "Selection: ";
}
void DisplayOptionsMenu()
{
cout << "Options Menu\n";
cout << "Please make your selection\n";
cout << "1 - Difficulty\n";
cout << "2 - Sound\n";
cout << "3 - Back\n";
cout << "Selection: ";
}
void Options()
{
int choice = 0;
do
{
system("cls");
DisplayOptionsMenu();
choice = GetInput();
switch(choice)
{
case 1:
cout << "difficulty stuff";
break;
case 2:
cout << "sound stuff";
break;
case 3:
break;
default:
break;
}
} while(choice!=3);
}
int main(int argc, char *argv[])
{
int choice = 0;
do
{
system("cls");
DisplayMainMenu();
choice = GetInput();
switch(choice) {
case 1:
cout << "Pew pew!\n";
break;
case 2:
Options();
break;
case 3:
cout << "Goodbye!";
break;
default:
break;
}
} while(choice!=3);
system("PAUSE");
return EXIT_SUCCESS;
}

I'd recommend that you change a few things here. Are you familiar with object-oriented design? If not, it's highly recommended that you read about that if you're looking to write code in C++ (Or just writing code in general, as it's a pretty major aspect of many programming languages)
Consider treating each of your menus and submenus as individual objects. Each time you enter the loop, use an object pointer to call a method that prints the current menu text.
Then, take the input from the user as normal, and change the menu object you're using now.
This is perhaps not the most ideal way to do a console menu, but it will give you a very strong grounding in how objected-oriented programming works.
I've attached an example :
#include <iostream>
#include <string>
class BaseMenu
{
public:
BaseMenu() { m_MenuText = "This shouldn't ever be shown!"; } // This is the constructor - we use it to set class-specific information. Here, each menu object has its own menu text.
virtual ~BaseMenu() { } // This is the virtual destructor. It must be made virtual, else you get memory leaks - it's not a quick explaination, I recommend you read up on it
virtual BaseMenu *getNextMenu(int iChoice, bool& iIsQuitOptionSelected) = 0; // This is a 'pure virtual method', as shown by the "= 0". It means it doesn't do anything. It's used to set up the framework
virtual void printText() // This is made virtual, but doesn't *have* to be redefined. In the current code I have written, it is not redefined as we store the menu text as a string in the object
{
std::cout << m_MenuText << std::endl;
}
protected:
std::string m_MenuText; // This string will be shared by all children (i.e. derived) classes
};
class FirstMenu : public BaseMenu // We're saying that this FirstMenu class is a type of BaseMenu
{
FirstMenu()
{
m_MenuText = "Main Menu\n" // What we are doing here is setting up the string to be displayed later
+ "Please make your selection\n" // What we are doing here is setting up the string to be displayed later
+ "1 - Start game\n" // What we are doing here is setting up the string to be displayed later
+ "2 - Options\n" // What we are doing here is setting up the string to be displayed later
+ "3 - Quit\n" // What we are doing here is setting up the string to be displayed later
+ "Selection: "; // What we are doing here is setting up the string to be displayed later
}
BaseMenu *getNextMenu(int choice, bool& iIsQuitOptionSelected) // This is us actually defining the pure virtual method above
{
BaseMenu *aNewMenu = 0; // We're setting up the pointer here, but makin sure it's null (0)
switch (choice) // Notice - I have only done "options". You would obviously need to do this for all of your menus
{
case 2:
{
aNewMenu = new SecondMenu; // We're creating our new menu object here, and will send it back to the main function below
}
case 3:
{
// Ah, they selected quit! Update the bool we got as input
iIsQuitOptionSelected = true;
}
default:
{
// Do nothing - we won't change the menu
}
}
return aNewMenu; // Sending it back to the main function
}
};
class SecondMenu : public BaseMenu
{
SecondMenu()
{
m_MenuText = "OptionsMenu\n"
+ "Please make your selection\n"
+ "1 - ????"
+ "2 - dafuq?";
}
BaseMenu *getNextMenu(int choice, bool& iIsQuitOptionSelected) // This is us actually defining the pure virtual method above
{
BaseMenu *aNewMenu = 0; // We're setting up the pointer here, but makin sure it's null (0)
switch (choice) // Notice - I have only done options. You would obviously need to do this for all of your menus
{
case 1:
{
aNewMenu = new FirstMenu; // We're creating our new menu object here, and will send it back to the main function below
}
break;
case 2:
{
aNewMenu = new FirstMenu; // We're creating our new menu object here, and will send it back to the main function below
}
break;
default:
{
// Do nothing - we won't change the menu
}
}
return aNewMenu; // Sending it back to the main function
}
};
int main (int argc, char **argv)
{
BaseMenu* aCurrentMenu = new FirstMenu; // We have a pointer to our menu. We're using a pointer so we can change the menu seamlessly.
bool isQuitOptionSelected = false;
while (!isQuitOptionSelected) // We're saying that, as long as the quit option wasn't selected, we keep running
{
aCurrentMenu.printText(); // This will call the method of whichever MenuObject we're using, and print the text we want to display
int choice = 0; // Always initialise variables, unless you're 100% sure you don't want to.
cin >> choice;
BaseMenu* aNewMenuPointer = aBaseMenu.getNextMenu(choice, isQuitOptionSelected); // This will return a new object, of the type of the new menu we want. Also checks if quit was selected
if (aNewMenuPointer) // This is why we set the pointer to 0 when we were creating the new menu - if it's 0, we didn't create a new menu, so we will stick with the old one
{
delete aCurrentMenu; // We're doing this to clean up the old menu, and not leak memory.
aCurrentMenu = aNewMenuPointer; // We're updating the 'current menu' with the new menu we just created
}
}
return true;
}
Note that this might be a bit complex for starting out. I strongly recommend you read the other answers people have posted. It should give you a few approaches on how to do it, and you can progress from the basic up to the more complex, examining each change.

Looking at what you are trying to do, I would change how you are ensuring the user still want's to play the game first. Look at using a while loop to check if a variable is true or false (people tend to use boolean variables(bool's) for this, an int set to 1 or 0 will do the same). That removes the need for the do-while. Reading up on control logic (if/else, while, for loops) and logical operators (&& - and, || - or, != - not equal to) is recommended. Control logic makes your code do different things, booleans are quick for checking yes/no scenarios and logical operators allow you to check multiple items in one if statement.
Some reading: Loops
Edit: Have more links for reading material, don't have the rep to post them.
Secondly, use another variable (int or whatever suits you) to track what screen you are on.
Based on this selection, display different options but still take input 1,2,3 to decide upon the next action.
In some terrible pseudo-code here is what I would lean towards:
main()
{
int choice
int screen = 1
bool running = true
while(running) {
//Screen 1, Main menu
if(screen == 1) {
cout << stuff
cout << stuff
cout << option 1
cout << option 2
cout << option 3
cout << selection:
cin >> choice
}
else if(screen == 2){
//options screen here
}
else {
//default/error message
}
//add some choice logic here
if(screen == 1 && choice == 3){
//being on screen one AND choice three is quit
running = false;
}
else if(screen == 1 && choice == 2){
//etc..
}
}
}
This is my first proper answer, all terrible criticism is well recieved.

Related

C++ program stuck in an infinite loop

Please note that I am a complete beginner at C++. I'm trying to write a simple program for an ATM and I have to account for all errors. User may use only integers for input so I need to check if input value is indeed an integer, and my program (this one is shortened) works for the most part.
The problem arises when I try to input a string value instead of an integer while choosing an operation. It works with invalid value integers, but with strings it creates an infinite loop until it eventually stops (unless I add system("cls"), then it doesn't even stop), when it should output the same result as it does for invalid integers:
Invalid choice of operation.
Please select an operation:
1 - Balance inquiry
7 - Return card
Enter your choice and press return:
Here is my code:
#include <iostream>
#include <string>
using namespace std;
bool isNumber(string s) //function to determine if input value is int
{
for (int i = 0; i < s.length(); i++)
if (isdigit(s[i]) == false)
return false;
return true;
}
int ReturnCard() //function to determine whether to continue running or end program
{
string rtrn;
cout << "\nDo you wish to continue? \n1 - Yes \n2 - No, return card" << endl;
cin >> rtrn;
if (rtrn == "1" and isNumber(rtrn)) { return false; }
else if (rtrn == "2" and isNumber(rtrn)) { return true; }
else {cout << "Invalid choice." << endl; ReturnCard(); };
return 0;
}
int menu() //function for operation choice and execution
{
int choice;
do
{
cout << "\nPlease select an operation:\n" << endl
<< " 1 - Balance inquiry\n"
<< " 7 - Return card\n"
<< "\nEnter your choice and press return: ";
int balance = 512;
cin >> choice;
if (choice == 1 and isNumber(to_string(choice))) { cout << "Your balance is $" << balance; "\n\n"; }
else if (choice == 7 and isNumber(to_string(choice))) { cout << "Please wait...\nHave a good day." << endl; return 0; }
else { cout << "Invalid choice of operation."; menu(); }
} while (ReturnCard()==false);
cout << "Please wait...\nHave a good day." << endl;
return 0;
}
int main()
{
string choice;
cout << "Insert debit card to get started." << endl;
menu();
return 0;
}
I've tried every possible solution I know, but nothing seems to work.
***There is a different bug, which is that when I get to the "Do you wish to continue?" part and input any invalid value and follow it up with 2 (which is supposed to end the program) after it asks again, it outputs the result for 1 (continue running - menu etc.). I have already emailed my teacher about this and this is not my main question, but I would appreciate any help.
Thank you!
There are a few things mixed up in your code. Always try to compile your code with maximum warnings turned on, e.g., for GCC add at least the -Wall flag.
Then your compiler would warn you of some of the mistakes you made.
First, it seems like you are confusing string choice and int choice. Two different variables in different scopes. The string one is unused and completely redundant. You can delete it and nothing will change.
In menu, you say cin >> choice;, where choice is of type int. The stream operator >> works like this: It will try to read as many characters as it can, such that the characters match the requested type. So this will only read ints.
Then you convert your valid int into a string and call isNumber() - which will alway return true.
So if you wish to read any line of text and handle it, you can use getline():
string inp;
std::getline(std::cin, inp);
if (!isNumber(inp)) {
std::cout << "ERROR\n";
return 1;
}
int choice = std::stoi(inp); // May throw an exception if invalid range
See stoi
Your isNumber() implementation could look like this:
#include <algorithm>
bool is_number(const string &inp) {
return std::all_of(inp.cbegin(), inp.cend(),
[](unsigned char c){ return std::isdigit(c); });
}
If you are into that functional style, like I am ;)
EDIT:
Btw., another bug which the compiler warns about: cout << "Your balance is $" << balance; "\n\n"; - the newlines are separated by ;, so it's a new statement and this does nothing. You probably wanted the << operator instead.
Recursive call bug:
In { cout << "Invalid choice of operation."; menu(); } and same for ReturnCard(), the function calls itself (recursion).
This is not at all what you want! This will start the function over, but once that call has ended, you continue where that call happened.
What you want in menu() is to start the loop over. You can do that with the continue keyword.
You want the same for ReturnCard(). But you need a loop there.
And now, that I read that code, you don't even need to convert the input to an integer. All you do is compare it. So you can simply do:
string inp;
std::getline(std::cin, inp);
if (inp == "1" || inp == "2") {
// good
} else {
// Invalid
}
Unless that is part of your task.
It is always good to save console input in a string variable instead of another
type, e.g. int or double. This avoids trouble with input errors, e.g. if
characters instead of numbers are given by the program user. Afterwards the
string variable could by analyzed for further actions.
Therefore I changed the type of choice from int to string and adopted the
downstream code to it.
Please try the following program and consider my adaptations which are
written as comments starting with tag //CKE:. Thanks.
#include <iostream>
#include <string>
using namespace std;
bool isNumber(const string& s) //function to determine if input value is int
{
for (size_t i = 0; i < s.length(); i++) //CKE: keep same variable type, e.g. unsigned
if (isdigit(s[i]) == false)
return false;
return true;
}
bool ReturnCard() //function to determine whether to continue running or end program
{
string rtrn;
cout << "\nDo you wish to continue? \n1 - Yes \n2 - No, return card" << endl;
cin >> rtrn;
if (rtrn == "1" and isNumber(rtrn)) { return false; }
if (rtrn == "2" and isNumber(rtrn)) { return true; } //CKE: remove redundant else
cout << "Invalid choice." << endl; ReturnCard(); //CKE: remove redundant else + semicolon
return false;
}
int menu() //function for operation choice and execution
{
string choice; //CKE: change variable type here from int to string
do
{
cout << "\nPlease select an operation:\n" << endl
<< " 1 - Balance inquiry\n"
<< " 7 - Return card\n"
<< "\nEnter your choice and press return: ";
int balance = 512;
cin >> choice;
if (choice == "1" and isNumber(choice)) { cout << "Your balance is $" << balance << "\n\n"; } //CKE: semicolon replaced by output stream operator
else if (choice == "7" and isNumber(choice)) { cout << "Please wait...\nHave a good day." << endl; return 0; }
else { cout << "Invalid choice of operation."; } //CKE: remove recursion here as it isn't required
} while (!ReturnCard()); //CKE: negate result of ReturnCard function
cout << "Please wait...\nHave a good day." << endl;
return 0;
}
int main()
{
string choice;
cout << "Insert debit card to get started." << endl;
menu();
return 0;
}

Summoning and Displaying a text file, inside a menu function

I'm quite new to C++ and my assignment is pretty tough. I must create a menu (in which I'm struggling quite badly), not only that but I should also read and display a textfile. So far, the only method I used only displays the first lines of the text file. Can you help me out? Thanks in advance.
The break function when added to the first case also makes the loop an infinite wall of texts! I dont know what to do..
// Assignment 1.cpp : Tally Ho Generator
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int runMenu;
int main()
{
int menuInput;
bool menu = true;
ifstream inFile;
string ABOUT;
// Menu Interface
cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
cout << " The Tally Ho Probability Generator (MCD4720_Assignment 1)\n";
cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
cout << " [1] End Testing the Program\n";
cout << " [2] Display About Information\n";
cout << " [3] Read and store data from files\n";
cout << " [4] Generate a Dice Tally Table\n";
cout << " [5] Save Tally Statistics to a file\n";
cout << " [6] Load Tally Statistics from a file\n";
cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
cout << "Which Option would you like (1-6)\n";
cin >> runMenu;
// Menu Input Function
while (menu != false) {
switch (runMenu)
{
case 1:
{
inFile.open("C:\\Users\\William\\Documents\\MCD Assignment 4720 1\\TallyAbout.txt");
while (getline(inFile, ABOUT)) {
cout << ABOUT << endl;
inFile.close();
}
break;
}
case 2:
{}
case 3:
{}
case 4:
{}
case 5:
{}
case 6:
{}
default: {
cout << " Input unrecognized, please choose again \n";
cin >> runMenu;
break;
}
}
}
cin.ignore();
cin.get();
return 1;
}
So far, the only method I used only displays the first lines of the text file
That is because you close the file after reading the first line:
while (getline(inFile, ABOUT)) {
cout << ABOUT << endl;
inFile.close(); // <------ here !!
}
You do not need to close the file explicitly. The file is closed in the destructor of inFile.
The break function when added to the first case also makes the loop an infinite wall of texts! I dont know what to do..
That is because break breaks out of the switch. No other case will be handled. In particular, your default case where you ask for user input will not be executed. Actually you never modify the value of menu and while(menu != false) is an infinite loop. Move the part that has to be done for any case out of the switch:
while (menu != false) {
switch (runMenu)
{
case 1:
{
inFile.open("C:\\Users\\William\\Documents\\MCD Assignment 4720 1\\TallyAbout.txt");
while (getline(inFile, ABOUT)) {
cout << ABOUT << endl;
inFile.close();
}
break;
}
//...
default: {
cout << " Input unrecognized, please choose again \n";
break;
}
}
cin >> runMenu;
// put logic here, for example:
menu = (runMenu == 1);
}
You should modify the output accordingly. Currently it says " Input unrecognized, please choose again ", but if I understand correctly, the user has to choose to continue or not on every iteration. Also using one and not two variables for menu and runMenu would be less error-prone.
Try this:
case 1:
{
inFile.open("C:\\Users\\William\\Documents\\MCD Assignment 4720 1\\TallyAbout.txt");
while (getline(inFile, ABOUT)) {
cout << ABOUT << endl;
}
inFile.close();
break;
}
You are closing the file after you read the first line
The difference now is that you close the file after you read all lines

What am I missing to call a function from the switch statement?

The switch can call the DisplayMenuChoice function, but any choice just ends the program.
All functions work fine independently, I think it has to do with my argument and return from DisplayMenuChoice
void GoblinSickDays();
void DisplayCoolMessage();
int DisplayMenuGetChoice (int)
{
int menu_choice;
cout << "Please select the following menu items: \n" << endl;
cout << "1. Enter Sick days." << endl;
cout << "2. Display Something cool." << endl;
cout << "3. End program \n" << endl;
cin >> menu_choice;
}
int main()
{
int menu_choice;
DisplayMenuGetChoice(menu_choice);
switch (menu_choice)
{
case 1: GoblinSickDays();
break;
case 2: DisplayCoolMessage();
break;
}
}
Keeps ending program after entering the a value from cin statement
It may be worth having a more in-depth understanding about the language syntax. Let me explain a few things in your code.
A typical function definition is as follows:
returnType FunctionName(paramType paramName)
{
returnType a = value;
return a;
}
To suit your current implementation, the function DisplayMenuGetChoice would likely be the following:
int DisplayMenuGetChoice()
{
int menu_choice;
{add your main logic here}
return menu_choice;
}
To break this down, it is:
A function named DisplayMenuGetChoice, callable by using DisplayMenuGetChoice()
Has a return type of int
By instead calling menu_choice = DisplayMenuGetChoice(); in your main() function, you will assign your menu_choice the value returned from DisplayMenuGetChoice().
An alternate approach (which seems to be what you are trying to achieve) is called Pass By Reference.. A parameter name is prefixed by an ampersand (&) to indicate this, for example:
void DisplayMenuGetChoice(int &menu_choice)
{
{add your main logic here}
}
This, by comparison:
We return void, which essentially means no return type.
We pass an int named menu_choice by reference. This is absolutely something you should read about.
We don't return anything as we modify menu_choice directly.
Now in the main function, you can instead use DisplayMenuGetChoice(menu_choice) instead.
As another small mention, by prefixing a variable with an ampersand (like you do in your function call), you are instead passing a pointer to the variable. This is a whole other topic that you may need to read up on.
Continuing from the comments above, when you pass a variable as a parameter, it is passed by value. Meaning the function receives a copy of the variable and any changes made to the variable in the function are not being made to the original back in main(), but instead are being made to the local copy within your function.
In C++ you have three basic ways of handling this:
pass a pointer to the variable as you would in C and update the value at that address within your function, e.g.
int DisplayMenuGetChoice (int *menu_choice) { ...
and call the function in main() as:
DisplayMenuGetChoice(&menu_choice);
you pass a reference to menu_choice and update the value directly within your function, e.g.
int DisplayMenuGetChoice (int& menu_choice) { ...
and call it as:
DisplayMenuGetChoice(menu_choice);
or finally don't worry about passing menu_choice at all. You have declared your DisplayMenuGetChoice as type int, so simply return menu_choice; from the function and assign the return back in main(), e.g.
int DisplayMenuGetChoice (void)
{
int menu_choice;
...
return menu_choice;
}
in main(),
int menu_choice = DisplayMenuGetChoice();
Putting it altogether in a couple of examples (ignoring the C solution), you could do:
Pass A Reference
int DisplayMenuGetChoice (int& menu_choice)
{
std::cout << "\nPlease select the following menu items: \n\n"
" 1. Enter Sick days.\n"
" 2. Display Something cool.\n"
" 3. End program\n\n"
"choice: ";
if (!(std::cin >> menu_choice)) {
std::cerr << "error: invalid integer input.\n";
exit (EXIT_FAILURE);
}
return menu_choice;
}
int main() {
int menu_choice;
DisplayMenuGetChoice(menu_choice);
switch (menu_choice) {
case 1: GoblinSickDays(); break;
case 2: DisplayCoolMessage(); break;
case 3: std::cout << "(bye)\n"; break;
default: std::cerr << "invalid choice.\n"; break;
}
}
Assign the Return
int DisplayMenuGetChoice (void)
{
int menu_choice;
std::cout << "\nPlease select the following menu items: \n\n"
" 1. Enter Sick days.\n"
" 2. Display Something cool.\n"
" 3. End program\n\n"
"choice: ";
if (!(std::cin >> menu_choice)) {
std::cerr << "error: invalid integer input.\n";
exit (EXIT_FAILURE);
}
return menu_choice;
}
int main() {
int menu_choice = DisplayMenuGetChoice();
switch (menu_choice) {
case 1: GoblinSickDays(); break;
case 2: DisplayCoolMessage(); break;
case 3: std::cout << "(bye)\n"; break;
default: std::cerr << "invalid choice.\n"; break;
}
}
Edit Per-Comment Re: do {...} while();
You can use any of the methods above to make the menu repeatedly redisplay until the user chooses to exit the program. For example, using any of the methods that return menu_choice you could do:
#include <iostream>
void GoblinSickDays()
{
std::cout << "Goblin is sick.\n";
}
void DisplayCoolMessage()
{
std::cout << "Cool Message.\n";
}
int DisplayMenuGetChoice (void)
{
int menu_choice;
std::cout << "\nPlease select the following menu items: \n\n"
" 1. Enter Sick days.\n"
" 2. Display Something cool.\n"
" 3. End program\n\n"
"choice: ";
if (!(std::cin >> menu_choice)) {
std::cerr << "error: invalid integer input.\n";
exit (EXIT_FAILURE);
}
return menu_choice;
}
int main() {
int done = 0;
do {
switch (DisplayMenuGetChoice()) {
case 1: GoblinSickDays(); break;
case 2: DisplayCoolMessage(); break;
case 3: std::cout << "(bye)\n";
done = 1;
break;
default: std::cerr << "invalid choice.\n"; break;
}
} while (!done);
}
(note: while the code above simply exits on a bad input, you should handle the error (whether it is cin.fail(), cin.bad() or cin.eof()) and so long as the error is recoverable, use std::basic_istream::ignore to remove the offending characters from stdin before the next time the menu is displayed)
Example Use/Output
$ ./bin/goblindays3
Please select the following menu items:
1. Enter Sick days.
2. Display Something cool.
3. End program
choice: 1
Goblin is sick.
Please select the following menu items:
1. Enter Sick days.
2. Display Something cool.
3. End program
choice: 2
Cool Message.
Please select the following menu items:
1. Enter Sick days.
2. Display Something cool.
3. End program
choice: 3
(bye)
Give that a try and let me know if you have further questions.
Look things over and let me know if you have further questions.

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;
}

loop not working?

After the call for Back to Main Menu, it returns to the mainMenu but when option or command is typed, the option is not accepted or the loop not working. Wonder where is the mistake? Is it extra call should be added or?
#include <iostream>
using namespace std;
char mainMenu(void);
int factorial(int n);
unsigned long long combination(long nK, long nR);
int main(){
char option;
int shape,function,i,j,k,t,n;
long nK, nR;
unsigned long long COM;
while((option=mainMenu())!='0')
{
switch(option)
{
case '1'://Program 1:
cout<< "*Drawing a shape\n"
<< "(1-Rectangle, 2-Triangle, 3-Inverted Triangle, 4-Letter 'H', 0-Back to Main Menu)\n";
do
{
cout<< "Choose shape >> ";
cin>> shape;
cout<< endl;
switch(shape)
{
case 1: break;
case 2: break;
case 3: break;
case 4: break;
case 0:
//Back to Main Menu
cout<< "Back to main menu\n"
<< endl;
return mainMenu(); //After here, it does back to Main Menu but command or option is not working
}
}while(shape!=0);
case '2': //Program 2
cout<< "*Choose function of calculator\n"
<< "(1-Factorial, 2-Combination, 0-Back to main menu)\n";
do
{
cout<< "Choose function >> ";
cin>> function;
cout<< endl;
switch(function)
{
case 1: break;
case 2: break;
case 0:
cout<< "Back to main menu\n"
<< endl;
return mainMenu();
}
}while(function!=0);
case '0':
cout<< "Program is terminating\n"
<< endl;
return 0;
default:
cout<< "Wrong input. Please choose one of the above options.\n"
<< endl;
return mainMenu();
}
}
}
char mainMenu(void){
char option;
cout<< "##############################\n"
<< "Main Menu\n"
<< "Enter your command!\n"
<< "##############################\n"
<< endl
<< "1. Program1\n"
<< "2. Program2\n"
<< "0. Exit\n"
<< endl
<< "Command >> ";
cin>> option;
cout<< endl;
return option;
}
I'm not sure what your question is, but your code is missing 2 important things. First, you need break statements at the end of each case block, otherwise the program flow will continue on to the next case statement.
Second, the inner menu doesn't ever escape the inner while(1) loop. This is a possible case for a goto use, although in practice it would better to refactor the code to split the top menu and inner menu into two functions, and use a return in the inner menu to return to the outer menu.
I'm not sure what your question is, but your code is missing 2 important things. First, you need break statements at the end of each case block, otherwise the program flow will continue on to the next case statement.
Second, the inner menu doesn't ever escape the inner while(1) loop. This is a possible case for a goto use, although in practice it would better to refactor the code to split the top menu and inner menu into two functions, and use a return in the inner menu to return to the outer menu.
As said, you're code is missing various things. It would be awesome if you distribute the entire code, and additionally the exact error message with line.
void value not ignored as it ought to be?...
...Is not that much of an explanation...
Also, are you sure you included iostream?
#include iostream
That said, you did not declare any of the variables used in the program.
You also missed a space in line 2 of your mainMenu() function.
Also, please tell us what you expected to happen.