2015-06-24 17 views
5

Po prostu nie mogłem zrozumieć, dlaczego ta prosta logika w pętli while nie działa.Dlaczego ta prosta logika nie działa?

Zasadniczo funkcja ta polega na tym, że pobiera argument i sprawdza w pętli while, czy nie jest "tak" czy "nie", a następnie zapętlanie.

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

Mimo że wpisuję "tak" lub "nie", nadal będzie się zapętlać.

+3

Zmień '||' na '&&'. – Maroun

+0

dlaczego && teraz jestem naprawdę zdezorientowany. podczas gdy nie tak lub nie nie, kontynuuj pętlę, jeśli "tak" lub "nie" przerwij pętlę – airsoftFreak

+0

Dodałem wyjaśnienie jako odpowiedź, ponieważ nie pasuje do komentarza. – Maroun

Odpowiedz

17

De Morgan's laws stwierdzają, że:

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

Stosowanie tego prawa na własną od stanu:

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

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

Teraz łatwiej zrozumieć, dlaczego jest źle.

Jeśli newAnswer jest czymś, co nie jest "Tak" lub "tak", zostanie ono ocenione jako prawdziwe, a to nie jest to, czego potrzebujesz.

Rozwiązanie zmieniłoby || na &&.

+0

Moja logika jest naprawdę zła, wstydzę się samego siebie. Jak ćwiczyć moją logikę? – airsoftFreak

+2

Nie powinieneś się wstydzić. Taki jest cel kłania się i ćwiczy. Próbuj dalej i pytaj, to jedyny sposób na naukę. Jesteś na dobrej drodze! Wciąż popełniam głupie błędy nawet po 5 latach programowania. – Maroun

+0

"Jak ćwiczyć swoją logikę?" Ćwicząc logikę. Doświadczenie wykonuje tę pracę. Jeśli to może pomóc, pomyśl o && jako "i jednocześnie ...". Chcesz, aby pętla zrywała się, gdy wprowadzona wartość jest "w tym samym czasie" inna niż wszystkie, które miałaś na myśli. Jest to równoznaczne z powiedzeniem "co najmniej" (przeciwieństwo "w tym samym czasie") równym (przeciwieństwo "innego") –

6

Pomyśl o tym. Proszę cię o tak lub nie. Powiedz mi "nie".

Przechodzę na swoją listę i kończę jako WKRÓTCE, kiedy dochodzę do prawdziwego stwierdzenia, ponieważ to właśnie oznacza logiczne OR.

newAnswer! = "Yes" >> true. Gotowe. Kontynuuj zapętlanie.

Dobrze, mówisz. Tym razem odpowiadasz "Tak".

newAnswer! = "Tak" >> fałszywe

newAnswer! = "Coś jeszcze" >> prawda. Gotowe. Kontynuuj zapętlanie.

To jest tautologia. Nie można uczynić tego warunku OR fałszywym. Powinieneś użyć AND.

W własnymi słowami, to nie jest „a nie tak lub nie” ale „a nie tak i nie nie i nie N, a nie y ...”

1

Logika jest następująca:

Jeśli wejście ciąg jest yes:

newAnswer != "yes" --> false 

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

Logicznym or kilku true s oraz jeden false jest true. Oznacza to, że dla wejścia wejścia yes pętla będzie kontynuowana. Jeśli zmienisz wszystkie te or s na and s, logiczne and z kilku s i jeden false będzie false. Jeśli wejście jest wejściem yes, pętla nie będzie kontynuowana.

2

Oprócz ewidentnej inwersji pomiędzy & & i || wszystkie odpowiedzi mówią, pozwól mi pójść trochę dalej, aby pokazać inny błąd (nie tak naprawdę błąd, ale słabość projektu): pytasz "tak lub nie" akceptujesz cokolwiek, a jeśli odpowiedź wygląda "tak", ty wyjście. Coś jeszcze gra jak nie. Nawet "jedna filiżanka kawy".

Odwracanie całej logiki ma tę samą wadę: sprawdź dla N, n, Nie, nie, aby zdecydować, że nie wyjdziesz oznacza wyjście, jeśli "herbata i herbatniki" są odbierane.

Również getAnswer trwa odpowiedzieć i wzywa chooseOptions (który z kolei dostanie jakiś wejście dać getAnswer): nie jesteś zapętlenie: jesteś recoursing. I robisz to samo (otrzymujesz odpowiedź z danych wejściowych) z dwóch różnych miejsc. Co się stanie, jeśli chcę zmienić std::cin z innym strumieniem? Wszystko do zmiany? W ilu różnych miejscach?

Znacznie lepsza logika powinna wymusić spójność odpowiedzi.

W swoim głównym programie należy zrobić najprawdopodobniej coś

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

Albo, bardziej zwięźle,

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 
} 

Teraz przejdźmy do logiki odpowiedź:

trzeba uzyskać jedną linię wejścia (nie tylko jedno słowo: jedna linia, ponieważ mogę wpisać "tak, chcę"), więc cin>>string nie gra dobrze: lepiej std::get_line. Jeśli "tak" zwróci true, jeśli "nie" zwróci false i jeśli cokolwiek innego powtórzy odczyt.

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

To sprawia, że ​​akceptujesz dobrze znane warianty "tak lub nie", ale odmawiasz niczego innego.

Idąc dalej, możemy sobie wyobrazić, że cin/cout może być innym rodzajem strumienia, i może być, że nie ma nikogo "piszącego".

Aby uniknąć iść w nieskończonej pętli, możemy wprowadzić limit próba i wyjątek, jeśli zostanie osiągnięty:

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

i niech rozmówca, aby w końcu złapać i zrobić kilka innych działań, lub ostatecznie z gracją zakończyć.

Co więcej, możemy parametryzować nie tylko i/o i pytania, ale także odpowiedzi, ale jest to zbyt daleko.

Powiązane problemy