Skip to content
← Back to Community
How to return to another line of code in c++
Profile icon
BFDMod

I am programming in c++ and making a food ordering app, first it shows the menu, then you pick something, then I want the program to to return to the line of code that shows the menu and you input what else you want.

For example if I had 100 lines of code, perimeters were met at line 80 to go back to line 8, how would I do that? Please answer if you can so I can finish this project! (sorry if my problem did not make sense to you!)

Answered by Geocube101 [earned 5 cycles]
View Answer
Voters
Profile icon
megraham
Profile icon
RishitaLolge
Profile icon
AquaMarine0421
Profile icon
BFDMod
Comments
hotnewtop
Profile icon
Geocube101

It is possible to place all of the code you need to rerun inside of an infinite while loop (with a specific condition to break the loop when necessary)

//Setup code here while (true) { //Looped Code Here }
Profile icon
BFDMod

@Geocube101
I'll give that a try! It does look like it can fix my problem, thanks for your time and effort!

Profile icon
Geocube101

@BFDMod
You're welcome

Profile icon
[deleted]

To tackle this problem let's focus on the core of what you need to solve, at least from what I'm able to extract from your code. Don't feel bad, this is a common problem with infinite complexity when a core piece of flow as

@Geocube101
has explain with looking into using a while loop. That is good advice. Context though can be hard when the rest of the code is adding so much overflow. So we'll strip this back down.

From your cout lines we have a menu...

//main menu std::cout <<"1. Sandwiches/Burgers\n2. Desert\n3. Meats\n4. Drinks\n"; //sandwiches std::cout <<"1. Chicken Sandwich\n2. Fish Sandwich\n3. Double Cheese Burger\n4. Cheese Burger\n5. Ham Sandwich\n6. Pork Sandwich\n"; //dessert std::cout <<"1. Sunday\n2. Root Beer Float\n3. Ice Cream Sandwich\n"; //meats std::cout <<"1. Chicken Breasts\n2. Baby Back Ribs\n3. Pork Loin\n4. Pulled Pork\n"; //drinks std::cout <<"1. Coke\n2. Pepsi\n3. Root Beer\n4. Fanta\n5. Cream Soda\n";

Lets ignore the prices for now and just how to handle the menu navigation. This can be tricky. So as mentioned a while loop would be handy, but so will an understanding of arrays, for loops, and a few other things. First let's get the string options addressed.

std::string mainMenu[] = { "Main", "Sandwiches/Burgers", "Desserts", "Meats", "Drinks" }; int mainMenuLen = 4;

This has several benefits. We can loop over it, it's easier to expand, modify, and we can also use a little hack to embed the menu as the first entry in the array. Why this works...

We want the menu to be ordered starting at 1. Since arrays in C/C++ are zero based if we have to use a for loop, it would traditionally follow something like this.

for(int i = 0; i < len; ++i) { std::cout << i << ". " << menuOption[i] << std::endl; }

This will start our menu at "0. Menu Option". So we would either need to i+1 in the output. Or we need to start the index of the for loop at 1 instead of 0.

for(int i = 1; i < len; ++i) { std::cout << i << ". " << menuOption[i] << std::endl; }

However, that means we would need to pad string array with an empty entry and then add the needed entries. This creates a gap. Inside the gap, we can store the Title and this saves us having to create other janky methods of either passing the title as argument to a function that displays the menu, or create another array of the title. It's just easier to store the title in that free space and it will be addressed as array[0] and then the menu items will start a array[1] and move forward so we get the proper display of the menu with no additional maths. This is a cleaner option and reduces complexity of the code for free.

We use a 2 dimensional array to setup the rest of the menu options...

std::string menuOptions[][6] = { { "Sandwich", "Chicken Sandwich", "Fish Sandwich", "Double Cheese Burger", "Ham Sandwich", "Pulled Pork Sandwich" },{ "Dessert", "Sunday", "Root Beer Float", "Ice Cream Sandwich" },{ "Meat", "Chicken Breast", "Baby Back Ribs", "Pork Loin", "Pulled Pork" },{ "Drink", "Coke", "Pepsi", "Root Beet", "Fanta", "Cream Soda" } }; int menuOptionsLen[] = {5, 3, 4, 5};

So now we have a reasonable setup that should be pretty easy to modify. We just need to make sure we track the last value correctly. Then we need to hook up some sort of function that can display the menus.

std::cout with all the << and other shenanigans. So we'll make a few little old school C style macros. Despite them being a violation of C++ standard, they are handy, reduce code complexity and clean up the mess that is C++ iostreams.

These are for handling some new line parsing and other formatting to save some typing and reduce the likelihood of an error.

#define print(format) std::cout << format #define printnl(format) print(format << std::endl) #define nlprint(format) print(std::endl << format) #define nlprintnl(format) printnl(std::endl << format)

Now let's tackle a menu display function.

It will need to take a couple arguments. We need the array with the menu options to display, and we'll need the last entry value. A for loop can be used to display the options and build the output. The title should be displayed and the menu options for input should also be displayed. A basic one might look something like...

void displayMenu(std::string array[], int last) { nlprintnl(array[0] << " Menu"); for(int i = 1; i <= last; ++i) { printnl(i << ". " << array[i]); } nlprintnl("Please select an option [1-" << last << "]:"); }

Then we can call it using...

void displayMenu(std::string array[], int last) { nlprintnl(array[0] << " Menu"); for(int i = 1; i <= last; ++i) { printnl(i << ". " << array[i]); } nlprintnl("Please select an option [1-" << last << "]:"); }

This is probably quite a bit to digest. And likely covering a huge amount of syntax you are completely unfamiliar with, so ask questions if you have them. Let's test the output, to make sure it's sort of doing close to what we need.

menu test

That doesn't look too terrible. I guess we are sort of on the right path. Okay. We still need to handle the input for the menu options. So let's address that. std::cin a real nightmare. I have posted in other sections of this forum how to parse/validate cinful input. This has way too many drawbacks. So we're going to create a custom getch to mimic the old unechoed DOS input that only reads a single character.

We need to add 2 headers.

termios.h gives us the ability to modify how the terminal acts
stdio.h allows us to use the C getchar to read a single character.

#include <termios.h> #include <stdio.h>

And write up the replacement. We'll use this to just read a single unechoed key. This is only useful in Linux. If you need a win32 modern replacement you can look here.

https://helloacm.com/modern-getch-implementation-on-windows-cc/

char getch() { tty working; char c; tcgetattr(0, &working); working.c_lflag &= ~ICANON; working.c_lflag &= ~ECHO; tcsetattr(0, TCSANOW, &working); c = getchar(); working.c_lflag |= ECHO; working.c_lflag |= ICANON; tcsetattr(0, TCSANOW, &working); return c; }

Some references:

https://www.daemon-systems.org/man/tcgetattr.3.html
http://man7.org/linux/man-pages/man3/termios.3.html

Basically we grab the current settings on the terminal.
Shut off the buffered i/o.
Disable echo to the console.
Read the character.
Turn buffered i/o back on.
Enable echo to console.
Return the character we read in.

We also need a few other little terminal hacks that work on linux only.

#define cls() std::cout << "\033[2J\033[0;0H" #define hideCursor() std::cout << "\033[?25l" #define showCursor() std::cout << "\033[?25h"

So now that we have a getch() replacement. We don't need to worry about all the janky std::cin stuffs and move on to validating the input. Once the menus are displayed we need to determine what menu option has been pressed. We know the limits 1 to last entry, those are simple enough to compare against in a switch statement to test for. We'll also want to do some ascii maths so we can convert the char literals that getch() is going to pass back. '1', '2', etc are not useful, but if we look up in an ASCII table...

ascii-table

This shows us that char literal '0' has a decimal value of 48. So '1' would be 49. So if we take our char stored in ch and subtract 48 from it once we have validated it, we will be able to get an int value of 1,2, etc. However, the array for the alternate menu options is 0 based for the first entry, so we can actually subtract 49 instead of 48 to get the correct offset off the main menu. When we validate the sub-menu items 48 can be used since we want the actual item selected. We'll need to write a special case for this.

Let's put this mess together with the control code for the input, expansion on the menus, and main loop to control flow.

#include <iostream> #include <termios.h> #include <stdio.h> typedef struct termios tty; std::string mainMenu[] = { "Main", "Sandwiches/Burgers", "Desserts", "Meats", "Drinks", }; int mainMenuLen = 4; std::string menuOptions[][6] = { { "Sandwich", "Chicken Sandwich", "Fish Sandwich", "Double Cheese Burger", "Ham Sandwich", "Pulled Pork Sandwich" },{ "Dessert", "Sunday", "Root Beer Float", "Ice Cream Sandwich" },{ "Meat", "Chicken Breast", "Baby Back Ribs", "Pork Loin", "Pulled Pork" },{ "Drink", "Coke", "Pepsi", "Root Beer", "Fanta", "Cream Soda" } }; int menuOptionsLen[] = {5, 3, 4, 5}; //std::cout print replacements #define print(format) std::cout << format #define printnl(format) print(format << std::endl) #define nlprint(format) print(std::endl << format) #define nlprintnl(format) printnl(std::endl << format) //terminal macros #define cls() std::cout << "\033[2J\033[0;0H" #define hideCursor() std::cout << "\033[?25l" #define showCursor() std::cout << "\033[?25h" char getch() { tty working; char c; tcgetattr(0, &working); working.c_lflag &= ~ICANON; working.c_lflag &= ~ECHO; tcsetattr(0, TCSANOW, &working); c = getchar(); working.c_lflag |= ECHO; working.c_lflag |= ICANON; tcsetattr(0, TCSANOW, &working); return c; } #define invalidInput -1 #define backSelected -2 #define checkoutSelected -3 #define quitSelected -4 int getValue(bool isMain, int last) { int r; for(char ch;;) { r = invalidInput; ch = getch(); if(ch >= '1' && ch <= (last + 48)) { r = ch - ((isMain) ? 49 : 48); } else if(isMain) { if(ch == 'c' || ch == 'C') r = checkoutSelected; else if(ch == 'q' || ch == 'Q') { r = quitSelected; } } else if((!isMain) && (ch == 'b' || ch == 'B')) { r = backSelected; } if (r != invalidInput) break; } return r; } void displayMenu(bool isMain, std::string array[], int last) { std::string extras; cls(); nlprintnl(array[0] << " Menu"); for(int i = 1; i <= last; ++i) { printnl(i << ". " << array[i]); } if (!isMain) { printnl("B. Go Back"); extras = "B"; } else { printnl("C. Checkout"); printnl("Q. Quit"); extras = "CQ"; } nlprintnl("Please select an option [1-" << last << " or " << extras << "]:"); } int main() { cls(); hideCursor(); bool looping = true; bool checkingOut = true; for(bool isMain = true; looping;) { int selection; if(isMain) { displayMenu(isMain, mainMenu, mainMenuLen); selection = getValue(isMain, mainMenuLen); switch (selection) { case checkoutSelected: checkingOut = true; case quitSelected: looping = false; break; } isMain = false; } else { displayMenu(isMain, menuOptions[selection], menuOptionsLen[selection]); selection = getValue(isMain, menuOptionsLen[selection]); if (selection != backSelected) { //loop up the value //store in some of transaction list //or just update some sort of tally counter } isMain = true; } } cls(); showCursor(); nlprint("end of line"); return 0; }

We still have some problems to address here. We have no way to attach values to the menu items. We also have not written the total, tabulation or checkout features and we have no method create a new order/clear an existing. In order order to deal with the menu items efficiently and attach a price, a structure with members is recommended. Let's draft that up.

typedef struct { std::string item; float cost; } TMenuItem;

Structs have members, in this case we have an item defined as a string, and a cost defined as floating point value. We have assigned it a name of TMenuItem. So we now have a custom type definition with that name. We can now think about upgrading the string array that is holding the menu options for the items.

TMenuItem mainMenu[] = { "Main", 0, "Sandwiches/Burgers", 0, "Desserts", 0, "Meats", 0, "Drinks", 0 }; TMenuItem menuOptions[][6] = { { "Sandwich", 0, "Chicken Sandwich", 2.22, "Fish Sandwich", 4.54, "Double Cheese Burger", 7.99, "Ham Sandwich", 5.45, "Pulled Pork Sandwich", 6.34 },{ "Dessert", 0, "Sunday", 2.99, "Root Beer Float", 1.79, "Ice Cream Sandwich", 0.89, },{ "Meat", 0, "Chicken Breast", 3.99, "Baby Back Ribs", 11.99, "Pork Loin", 9.56, "Pulled Pork", 8.65, },{ "Drink", 0, "Coke", 0.99, "Pepsi", 0.99, "Root Beer", 0.99, "Fanta", 0.99, "Cream Soda", 1.29 } };

This prompts that we also need to update the displayMenu function and make a few other changes to display the cost on the menu items, write a janky pad function as std::string along with most of the std::namespace is nightmare. printf in C has much nicer and way easier to use string manipulation for formatting. That's a talk for another time. Let's get this updated.

void displayMenu(bool isMain, TMenuItem array[], int last) { cls(); nlprintnl(array[0].item << " Menu"); for(int i = 1; i <= last; ++i) { print(i << ". " << array[i].item); if(!isMain) { std::string cost = toStr(array[i].cost); std::string pad = std::string(35 - array[i].item.length(), ' '); printnl(pad << "$" << cost); } else { print(std::endl); } } std::string extras; if (!isMain) { printnl("B. Go Back"); extras = "B"; } else { printnl("C. Checkout"); printnl("Q. Quit"); extras = "CQ"; } nlprintnl("Please select an option [1-" << last << " or " << extras << "]:"); }

That is so janky. As C coder, C++ totes all these benefits, and you end up with that nightmare of a function. If any of you other C++ coders know of an easier way to implement that, please post a reply. I am not a C++ coder, so took some liberties with some google fu trying to find a solution. Criticise that at will. It is seriously janky.

With that out of the way, this should give you enough code to be able to sort out the rest. I strongly urge you to look up std::vector for building your order list. And write out some of display. Add in an order reset, or extend some deeper functionality to allow replacing, removing and updating an order list. Would also be useful to show on the main menu what the current order is, and to display the tally. Hope this helps... Here's the last iteration of the code as a whole.

#include <iostream> #include <termios.h> #include <stdio.h> #include <sstream> #include <string> template <typename Type> std::string toStr(const Type & t) { std::ostringstream os; os << t; return os.str (); } typedef struct termios tty; typedef struct { std::string item; float cost; } TMenuItem; TMenuItem mainMenu[] = { "Main", 0, "Sandwiches/Burgers", 0, "Desserts", 0, "Meats", 0, "Drinks", 0 }; int mainMenuLen = 4; TMenuItem menuOptions[][6] = { { "Sandwich", 0, "Chicken Sandwich", 2.22, "Fish Sandwich", 4.54, "Double Cheese Burger", 7.99, "Ham Sandwich", 5.45, "Pulled Pork Sandwich", 6.34 },{ "Dessert", 0, "Sunday", 2.99, "Root Beer Float", 1.79, "Ice Cream Sandwich", 0.89, },{ "Meat", 0, "Chicken Breast", 3.99, "Baby Back Ribs", 11.99, "Pork Loin", 9.56, "Pulled Pork", 8.65, },{ "Drink", 0, "Coke", 0.99, "Pepsi", 0.99, "Root Beer", 0.99, "Fanta", 0.99, "Cream Soda", 1.29 } }; int menuOptionsLen[] = {5, 3, 4, 5}; //std::cout print replacements #define print(format) std::cout << format #define printnl(format) print(format << std::endl) #define nlprint(format) print(std::endl << format) #define nlprintnl(format) printnl(std::endl << format) //terminal macros #define cls() std::cout << "\033[2J\033[0;0H" #define hideCursor() std::cout << "\033[?25l" #define showCursor() std::cout << "\033[?25h" char getch() { tty working; char c; tcgetattr(0, &working); working.c_lflag &= ~ICANON; working.c_lflag &= ~ECHO; tcsetattr(0, TCSANOW, &working); c = getchar(); working.c_lflag |= ECHO; working.c_lflag |= ICANON; tcsetattr(0, TCSANOW, &working); return c; } #define invalidInput -1 #define backSelected -2 #define checkoutSelected -3 #define quitSelected -4 int getValue(bool isMain, int last) { int r; for(char ch;;) { r = invalidInput; ch = getch(); if(ch >= '1' && ch <= (last + 48)) { r = ch - ((isMain) ? 49 : 48); } else if(isMain) { if(ch == 'c' || ch == 'C') r = checkoutSelected; else if(ch == 'q' || ch == 'Q') { r = quitSelected; } } else if((!isMain) && (ch == 'b' || ch == 'B')) { r = backSelected; } if (r != invalidInput) break; } return r; } void displayMenu(bool isMain, TMenuItem array[], int last) { cls(); nlprintnl(array[0].item << " Menu"); for(int i = 1; i <= last; ++i) { print(i << ". " << array[i].item); if(!isMain) { std::string cost = toStr(array[i].cost); std::string pad = std::string(35 - array[i].item.length(), ' '); printnl(pad << "$" << cost); } else { print(std::endl); } } std::string extras; if (!isMain) { printnl("B. Go Back"); extras = "B"; } else { printnl("C. Checkout"); printnl("Q. Quit"); extras = "CQ"; } nlprintnl("Please select an option [1-" << last << " or " << extras << "]:"); } int main() { cls(); hideCursor(); bool looping = true; bool checkingOut = true; for(bool isMain = true; looping;) { int selection; if(isMain) { displayMenu(isMain, mainMenu, mainMenuLen); selection = getValue(isMain, mainMenuLen); switch (selection) { case checkoutSelected: checkingOut = true; case quitSelected: looping = false; break; } isMain = false; } else { displayMenu(isMain, menuOptions[selection], menuOptionsLen[selection]); selection = getValue(isMain, menuOptionsLen[selection]); if (selection != backSelected) { //loop up the value //store in some of transaction list //or just update some sort of tally counter } isMain = true; } } cls(); showCursor(); nlprint("end of line"); return 0; }

I'm sure you're going to have questions, ask... I'll be more than happy to expand on this. Keep your stick on the ice.

Profile icon
AquaMarine0421

Hello BFDMod! I am not an expert coder, but I will tell you some solutions.
First of all, you can use goto(). goto is a function that helps you "go to" a part of your code. It is out-of-use, though, because using so many goto functions will harden your ability to distinguish how the algorithm flows.
Second of all, if you are not familiar with goto, then feel free to ask me anytime, I will try my best to solve your problem!

*edit: sorry! I thought you were programming in c for a sec. Goto is a function which is used in c, and I cannot think of a thing that does any similar thing in c++. I recommend you use c for this project, and if you just want to program in C++ then I will try my best to help you
:-) Best wishes, Aqua!

Profile icon
BFDMod

@AquaMarine0421
Thank you for your help, it is fine if you don't know how to do this, I will just find a work around for now because I have tried to figure it out for so long. I might take your advice for learning c later but for now im sticking with c++ because this is the 6th programming language i've learned and I am only 15 so i'll give it some time lol! Again thank you for taking the time to try and help me with my issue and I hope your next/current project goes as smooth as they really can!

Profile icon
ash15khng

@BFDMod
it's generally bad practice to use goto, so try not to use it. You could try using a loop instead.

Profile icon
BFDMod

@ash15khng
could you explain the basic syntax of a loop please?

Profile icon
etian

its not relly smth about this but if you want, you can using namespace std; b4 int main and it'll let you not have to write std::@BFDMod

Profile icon
[deleted]

@AquaMarine0421
do not advise a new programmer to use GOTO statements. you do not want to touch that spaghet. There is only one case where it can be required in C, when you need to escape multiple nests of a for loop. Outside that, there is almost guaranteed to be a better way to write code.

Profile icon
AquaMarine0421

@KelvinVerhey
thank you for your advice, I am also not that good at programming :)

Profile icon
[deleted]

@AquaMarine0421
Bad habits are hard to break. Better just to avoid them. Keep your head up. Never stop programming, and enjoy the journey. It's a worthy one that opens doors to possibility. Study lots of code, as much as you can. Over time you'll see things. I like to just practice on little snippets of code looking for better ways to tackle a problem. Sat down last night before going out for a walk and took a snippet from another piece of repl.it share on practicing with binary search trees.

Original:

void Tcase(Node** root){ int data = 0; while(1){ scanf("%d",&data); if(data==0) break; createBST(root,data); } }

It's not terrible code, but it's a little janky. So thought about trying to get rid of that silly break creating a little bit of spaghetti in the middle of the while.

Attempt 1

void Tcase(Node** root){ int data = 0; do { scanf("%d",&data); if(data != 0) createBST(root,data); } while (data != 0); }

This doesn't really improve much. Added two conditionals, but it does get rid of the break. Not really impressed with that one.

Attempt 2

void Tcase(Node** root){ int data = 0; do { scanf("%d",&data); if(data) createBST(root,data); } while (data != 0); }

The janky expression for the != test in the if expression. Just flipped that, but still didn't really improve much. Thought of maybe dumping the while and possibly messing around with a for loop instead.

Attempt 3

void Tcase(Node** root){ int data = 0; for(;;) { scanf("%d",&data); if(data) createBST(root,data); else break; } }

This forced me to put some of the break spaghetti back in, and in some ways made this worse than original.

Attempt 4

void Tcase(Node** root){ for(int data;;) { scanf("%d",&data); if(data) createBST(root,data); else break; } }

At least we can dump the declaration of the int and embed it into the for. But this still isn't really any better than the original. Really needed to dig deep. So looked at for about 10 minutes, wrote about another 5 or 6 variations... and arrived at this.

Attempt that was more acceptable...

void Tcase(Node** root){ for(int data = 1; !data;) { scanf("%d",&data); if(data) createBST(root,data); } }

This still requires two expression checks. We need to also set the value of data initially to 1 so the for loop doesn't bail on first loop. I'm still not happy with that. So woke up this morning and thinking maybe you can drop the conditional inside the for, and convert the other expression to a ternary.

Attempt to convert to a ternary if...

void Tcase(Node** root){ for(int data = 0;;) { scanf("%d",&data); (data) ? createBST(root,data) : break; } }

Unfortunately, you cannot put a break there in the way ternary ifs evaluate their parts... but you could do a janky space exploit and modify Attempt 4. Still dump the second evalution and get a single expression with an exit condition that happens at the tail. And you're not really adding complexity. Still the have the ability to clean up the code for simplicity.

Attempt 4 [shrunk]

void Tcase(Node** root){ for(int data = 0;;) { scanf("%d",&data); if(data) createBST(root,data); else break; } }

Could this still be improved? Is there a better way to mess around with this? I'm not a fan of compressing ifs like that. Is there limitations in the language? There are so many different ways to write code.

Conclusion

void Tcase(Node** root){ for(int data;;) { scanf("%d",&data); if(!data) break; createBST(root,data); } }

Write more code... lots of it. Pick it apart. I'm still not a fan of needing that break before adding a node. But it does imply the else. The while can still be dropped in place of a for with initialiser and the == 0 can be swapped for a ! check instead. This still doesn't address the validation of the scanf. Which is a real problem. But for a little coding exercise to mess around a little, it does help with understanding.