goto command not working as expected

I solved this with a loop but in the process I couldn't get the goto to work as expected.

This ends in an infinite loop. Obviously the last if statement is the culprit but how? If I press "n" or "y" it still stays in the loop. Play_again is a flag that tells the outer loop to stop.

1
2
3
4
5
6
7

re_ask:
cout<<"Would you like to play again? ";
			cin>>again;
			if (again=='n'){play_again = 0;}
			if (again=='y'){play_again = 1;}
			if (again!='n' || again!= 'y'){goto re_ask;}         

Last edited on
The if condition of the third if statement is always true. There is no way again can be equal to 'n' and 'y' at the same time.
If you are using a loop then why do you still have a goto? Don't use a goto for this. Break it into a function.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
bool ask_play_again()
{
  while (true)
  {
    cout << "Would you like to play again? ";
    string ans;
    cin >> ans;
    switch (ans.c_str()[0])
    {
      case 'Y': case 'y': return true;
      case 'N': case 'n': return false;
      default: cout << "You didn't answer the question.\n";
    }
  }
1
2
3
4
5
6
  while (true)
  {
    ...

    if (!ask_play_again()) break;
  }

Hope this helps.
Thanks. I have a loop, but wanted to complete the goto as a thought exercise. I had a lot of loops and wanted to simplify it a little. My loop...

1
2
3
4
5
6
7
while(flag){
			cout<<"Would you like to play again? ";
			cin>>again;
			if (again=='n'){play_again = 0;flag = 0;} // play_again terminates another loop
			if (again=='y'){play_again = 1;flag = 0;}
			if (again!='n' || again!= 'y'){;}           
			}


Peter 87 I don't see where the third statement is always true. It will only be true if again is not "n" OR not "y". If user puts in a nonsensical response the program is redirected to asking it again until a sensical response is obtained.
If again is "n", then it is not "y" so the expression will be true.
If again is "y", then it is not "n" so the expression will be true.

A logical OR expression is true whenever either (or both) of the evaluated expressions is true.
Hi,

I am not trying to be harsh or rude or anything, but:

I would advise abandoning messy, non-scalable, ugly & error prone statements like the ones you have on line 6, and follow what Duoas has said :+)

Just trying to promote doing things correctly :+)
closed account (48T7M4Gy)
Sounds like a relatively simple pencil+paper flow charting exercise would provide a bit of insight here too.
Last edited on
closed account (48T7M4Gy)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>

using namespace std;

int main()
{
    char again = '0';
    re_ask:
        cout<<"Would you like to play again? ";
        cin>>again;
        
			if (again=='n'){cout << "play_again = 0" << endl;}
			if (again=='y'){cout << "play_again = 1" << endl;}
			if (again!='n' || again!= 'y'){cout << "re-ask" << endl; goto re_ask;}
			
		return 0;
}


Would you like to play again? x
re-ask
Would you like to play again? y
play_again = 1
re-ask
Would you like to play again? n
play_again = 0
re-ask
Would you like to play again? 0
re-ask
Would you like to play again?  

> goto as a thought exercise

Typical use of goto:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
play:
        // play game

ask:
        char again ;
        std::cout << "again (y/n)?" ;
        std::cin >> again ;

        if( again == 'y' || again == 'Y' ) goto play ;
        else if ( again == 'n' || again == 'N' ) goto finish ;
        else goto ask ;

finish:
        std::cout << "bye!\n" ;
        // end program 
The thing that trips people up with loops like this is that the exit condition is in the middle of the loop, not the beginning or the end. Rather than fighting it, just code it that way. The general pattern is
1
2
3
4
5
6
7
while (true) {
   get the input
   if (input is valiid) {
        process input
        break;
   }
}


In your case:

1
2
3
4
5
6
7
8
9
10
11
while (true) {
    cout<<"Would you like to play again? ";
    cin>>again;
    if (again=='n'){
        play_again = 0;
        break;
    } else if (again=='y'){
        play_again = 1;
        break;
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
bool play_again()
{
    char again ;
    do
    {
        std::cout << "Would you like to play again (y/n)? ";
        std::cin >> again ;
        again = std::tolower(again) ;
    }
    while( again != 'y' && again != 'n' ) ;

    return again == 'y' ;
}
JL thanks for humoring me on the goto, i don't know I got so turned around on something so simple.

I was wrong about the third line it is always true. I took it out with the same result:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include<iostream>

using namespace std;

int main()
{
	char again;
	bool flag(1), play_again(0);
	while(flag){
				cout<<"Would you like to play again? ";
				cin>>again;
				if (again=='n'){play_again = 0;flag = 0;} // play_again terminates another loop
				if (again=='y'){play_again = 1;flag = 0;}
				//if (again!='n' || again!= 'y'){;}
				}

//---> remove bottom line above

cout<<"out";
	return 0;
}


Would you like to play again? f
Would you like to play again? s
Would you like to play again? m
Would you like to play again? y
out


dhayden thx for posting

The thing that trips people up with loops like this is that the exit condition is in the middle of the loop, not the beginning or the end. Rather than fighting it, just code it that way. The general pattern is


sage advice

are break commands well accepted in the programming community for programming flow and control? I don't mean this in the pejorative, I just have no idea.

Ideally this code could be dispatched as a function, predicated on a switch statement or a series of whiles and/or breaks.

I am not trying to be harsh or rude or anything, but:

I would advise abandoning messy, non-scalable, ugly & error prone statements like the ones you have on line 6, and follow what Duoas has said :+)


Messy, ugly and probably error prone I see; but non-scalable? : )
Last edited on
> are break commands well accepted in the programming community

I guess it largely depends on the specific subset of the 'programming community'.

Of the four jump statements (break, continue, goto and return), the only ones that are universally accepted without reservations are return and break within a switch statement.

The jump statements which unconditionally transfer control to another statement in the current function (continue, goto and break within an iteration statement) are often looked upon less favourably. Contexts in which use of one of these is the best available option are somewhat rare; of the lot, contexts in which goto is the best available option are extremely rare.
Messy, ugly and probably error prone I see; but non-scalable? : )


I quite often see this code which is in conjunction with a menu, and am dismayed by it:

if (option != 'a' && option != 'b' && option != 'c' && option != 'd' && option != 'e' /* etc */) {}

I also see this as the condition in loops.

A much better option IMO, is a switch which is scalable - one could have say 20 or 100 cases in a switch. Particularly the default case, which does the same job as the messy if statement.

An example of this might be a program to convert assembly op-codes and their arguments to binary. There is an enum and a case for each op code.

JLBorges has a short version in his code above, but that only deals with a y / n question, I wouldn't have anything more than that. It could still be done with a switch - there are 3 cases: y, n or default for bad input.

> one could have say 20 or 100 cases in a switch.

Not a particularly palatable idea; try reading code which has a switch with 20+ cases.
For validation, I prefer something like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
char choice()
{
    static const std::string valid = "abcdefghijkl" ;

    char selection ;
    do
    {
        std::cout << "select one of " << std::quoted(valid) << "? ";
        std::cin >> selection ;
        selection = std::tolower(selection) ;
    }
    while( valid.find(selection) == std::string::npos ) ;

    return selection ;
}
@JLBorges

We can always rely on you to provide an excellent and elegant answer :+)

Although the example I had in mind was stuck in ancient history - the op-code to binary thing was in C for a school boy type assignment. So rather than implement a find algorithm, it was easier to have massive enum, switch and a function for each one as well. Reading the code for the switch wasn't so bad, because each case called a function. There was another function which converted register names to numbers.

But your code is much better with c++, it's easy to see how that could be extended to use a std::vector<std::tuple<std::string, std::string, std::function>> to take care of op-codes and their arguments and a function to process them.

Cheers
are break commands well accepted in the programming community for programming flow and control?

In addition to whay JLBorges has said, I'll add that if using a break or return makes the code cleaner and easier to read, then by all means use it. I've seen "purist" code that avoids breaks, insists on one return statement per function, and is nearly impossible to read as a result.

Not a particularly palatable idea; try reading code which has a switch with 20+ cases.

Quite true. In cases like this, I've used a table of function pointers instead.
Hey T.I.M thx for the scalable. Good habits.

Thank you everyone.
Last edited on
Topic archived. No new replies allowed.