Why does this simple logic not work?

I simply could not understand why this simple logic in the while loop does not work.

Basically what the function does, it takes an argument and checks the while loop to make sure that if it is not β€œyes” or β€œno,” then continue the loop.

void getAnswer(string answer) { string newAnswer = ""; newAnswer = answer; while (newAnswer != "Yes" || newAnswer != "yes" || newAnswer != "Y" || newAnswer != "y" || newAnswer != "No" || newAnswer != "no") { cout << "Enter yes or no.." << endl; cin >> newAnswer; } if (newAnswer == "Yes" || newAnswer == "yes" || newAnswer == "Y" || newAnswer == "y") { chooseOptions(); } else { cout << "Bye See you again " << endl; exit(1); } } 

But even if I enter yes or no, it will still loop.

+5
source share
4 answers

De Morgan's laws state that:

 "not (A and B)" is the same as "(not A) or (not B)" 

Applying this law to your discretion:

 newAnswer != "Yes" || newAnswer != "yes" || ... 

⇔

 !(newAnswer == "Yes" && newAnswer == "yes" && ...) 

Now it’s easier to understand why this is wrong.

If newAnswer is something that is not β€œyes” or β€œyes,” it will be evaluated as true, and that is not what you want.

The decision will change || at && .

+17
source

Think about it. I ask you yes or no. You say no to me.

I go down my list and stop like SOON when I get a true statement because that is what logical OR means.

newAnswer! = "Yes" β†’ true. Done. Continue the cycle.

Ok, you say. This time you say yes.

newAnswer! = "Yes" β†’ false

newAnswer! = "anything else" β†’ true. Done. Continue the cycle.

This is a tautology. This condition cannot be made OR false. You must use AND.

In your opinion, this is not "not yet yes or no", but "not yet, not no And not n And not at ..."

+6
source

Besides the obvious inversion between && and || all the answers to the questions, let me go a little further to make another mistake obvious (in fact, not a mistake, but a design weakness): you ask yes or no, accept something, and if the answer looks yes, you exit. Everything else plays like no. Even "one cup of coffee."

And inverting the whole logic has the same error: check for N, n, No, no, to decide not to go out, then go out if they answer β€œtea and cookies”.

In addition, getAnswer accepts the answer and calls to chooseOptions (which in turn will receive some input to give getAnswer ): you are not looping: you are returning. And you do the same thing (get a response from the input) from two different places. What happens if I want to change std::cin with some other thread? Anything to change? How many different places?

Better logic should make the answer be consistent.

In your main program, you should do something like

 bool do_exit = false; while(!do_exit) { //All useful stuff and then ... do_exit = getAnswer(std::cin, std::cout, "Do you want to exit? [yes/no]", "please answer yes or no"); } 

Or, more briefly,

 for(bool do_exit=false, !do_exit, do_exit=getAnswer( "Do you want to exit? [yes/no]", "please answer yes or no") ) { //usefull stuff here } 

Now let's move on to the logic of the answer:

You should get one line of input (not one word: one line, since I can enter "yes, I want"), so cin>>string does not play well: std::get_line . If yes, return true, if no returns false and if something else repeats the read.

 bool getAnswer(std::istream& istr, std::ostream& ostr, const std::string& prompt, const std::string& reprompt) { ostr << prompt << std::endl; for(;;) { std::string line; std::getline(istr,line); if(line == "yes" || line == "Yes" || line == "Y" || line == "y") return true; if(line == "no" || line == "No" || line == "N" || line == "n") return false; ostr << reprompt << std::end; } } 

This forces you to accept the well-known yes or no options, but refuse anything else.

Going even further, we can grasp the idea that cin / cout may be other types of streams, and maybe no one "prints".

To avoid going into an infinite loop, we can introduce a restriction on the attempt and throw an exception if it is reached:

 bool getAnswer(std::istream& istr, std::ostream& ostr, const std::string& prompt, const std::string& reprompt) { ostr << prompt << std::endl; for(int attempt=5; attempt>0; --attempt) { std::string line; std::getline(istr,line); if(line == "yes" || line == "Yes" || line == "Y" || line == "y") return true; if(line == "no" || line == "No" || line == "N" || line == "n") return false; if(attempt>1) ostr << reprompt << " ("<<attempt-1<<" attempts remaining)"<<std::endl; } throw std::domain_error("cannot get valid input"); } 

and let the caller eventually catch and perform some other action or, ultimately, gracefully complete the job.

In addition, we can parameterize not only i / o and questions, but also answers, but this is too far.

+2
source

The logic is as follows:

If your line input is yes :

 newAnswer != "yes" --> false newAnswer != "Yes" --> true newAnswer != "Y" --> true newAnswer != "y" --> true newAnswer != "No" --> true newAnswer != "no" --> true 

Boolean or several true and one false - true . This means that to enter the input yes cycle will continue. If you change all of these or to and s, the logical and of several is true and one false will be false . If the input is yes , the loop will not continue.

+1
source

All Articles