2015-06-24 2 views
5

Я просто не мог понять, почему эта простая логика во время цикла не работает.Почему эта простая логика не работает?

В основном, что делает функция, она принимает аргумент и проверяет цикл while, чтобы увидеть, не является ли он «да» или «нет», а затем продолжать цикл.

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

Но даже если я введу «да» или «нет», он все равно будет зацикливаться.

+3

Измените '||' на '&&'. – Maroun

+0

why && теперь я действительно смущен. в то время как нет да или нет нет, тогда продолжайте цикл, если «да» или «нет», затем перерыв цикла – airsoftFreak

+0

Я добавил объяснение в качестве ответа, так как он не соответствует комментариям. – Maroun

ответ

17

De Morgan's laws гласят:

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

Применяя этот закон на ваши на вашем состоянии:

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

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

Теперь легче понять, почему это неправильно.

Если newAnswer - это то, что не является «да» или «да», оно будет оценено как истинное, и это не то, что вы хотите.

Решение будет меняться || на &&.

+0

Моя логика очень плохая, мне стыдно за себя. Как мне практиковать мою логику? – airsoftFreak

+2

Вам не должно быть стыдно. Это и есть цель наклоняться и практиковать. Продолжайте пытаться и спрашивать, это только способ обучения. Вы на правильном пути! Я все еще делаю глупые ошибки даже после 5 лет программирования. – Maroun

+0

«Как мне практиковать мою логику?» Практикуя логику. Опыт делает работу. Если это может помочь, подумайте о && как «и в то же время ...». Вы хотите, чтобы цикл прерывался, когда введенное значение «в то же время» отличается от всех, что вы имели в виду. Это то же самое, что сказать «по крайней мере» (противоположное «в то же время») равное (противоположное «другому») –

6

Подумайте об этом. Я спрашиваю вас, да или нет. Вы говорите мне «нет».

Я иду вниз по своему списку и останавливаюсь как СКОРО, когда я получаю истинное утверждение, потому что это то, что означает логический ИЛИ.

новыйAnswer! = "Yes" >> true. Готово. Продолжить цикл.

Отлично, вы говорите. На этот раз вы ответите «Да».

newAnswer! = "Да" >> ложь

newAnswer! = "Все остальное" >> правда. Готово. Продолжить цикл.

Это тавтология. Невозможно сделать это условие ИЛИ ложным. Вы должны использовать AND.

своими словами, это не «а не да или нет», но «пока не да и не нет и не п И не у ...»

1

Логика заключается в следующем:

Если входная строка является yes:

newAnswer != "yes" --> false 

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

Логическим or нескольких true с и один false является true. Это означает, что для ввода входного сигнала yes цикл будет продолжен. Если вы измените все эти s на and s, то логический and из нескольких true s и один false будет false. Если вход представляет собой вход yes, цикл не будет продолжаться.

2

Помимо очевидной инверсии между & & и || все ответы на вопросы, позвольте мне пойти немного дальше, чтобы сделать еще одну ошибку очевидной (на самом деле не ошибка, а слабость дизайна): вы спрашиваете «да или нет», что-нибудь примите, и если ответ выглядит «да», вы Выход. Все остальное играет как нет. Даже «одна чашка кофе».

И инвертирование всей логики имеет ту же ошибку: проверьте для N, n, No, no, чтобы решить не выходить, означает выход, если на «чай и печенье» отвечают.

Кроме того, getAnswer принимает ответ и вызывает chooseOptions (который, в свою очередь получит некоторые вход, чтобы дать getAnswer): вы не зацикливание: вы recoursing. И вы делаете то же самое (получите ответ от ввода) из двух разных мест. Что произойдет, если я хочу изменить std::cin с каким-то другим потоком? Все, что нужно изменить? Сколько разных мест?

Лучшая логика должна заставлять ответ быть последовательным.

В главной программе вы должны сделать, скорее всего, что-то вроде

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

Или, более сжато,

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 
} 

Теперь, позволяет получить в ответ логики:

Вы должны получить одну строку ввода (не только одно слово: одна строка, так как я могу набрать «да, я хочу»), поэтому cin>>string не играет хорошо: лучше std::get_line. Если это «да», верните true, если «no» вернет false и если что-то еще повторит чтение.

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

Это заставляет вас принять хорошо известные варианты «да или нет», но отказаться от чего-либо еще.

Идя еще дальше, мы можем уяснить мысль о том, что cin/cout может быть другим видом потоков, и может быть, никто не «печатает».

Чтобы избежать идти в бесконечном цикле, можно ввести ограничение попытки и выбросить исключение, если оно будет достигнут:

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

и пусть вызывающие в конечном итоге поймать и сделать некоторые другие действия, или в конце концов, изящно прекращается.

Кроме того, мы можем параметризовать не только вопросы и ответы, но и ответы, но это слишком далеко.

Смежные вопросы