2015-06-24 23 views
5

Non riuscivo a capire perché questa semplice logica nel ciclo while non funzioni.Perché questa semplice logica non funziona?

Fondamentalmente ciò che la funzione fa è che, accetta un argomento e controllerà il ciclo while per vedere se non è "sì" o "no", quindi continua il ciclo.

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

Ma anche se inserisco "sì" o "no", continuerà a girare.

+3

Cambia '||' in '&&'. – Maroun

+0

why && now I'm really confused. mentre non si o no no, continua a ripetere il ciclo, se "si" o "no", quindi interrompi il ciclo – airsoftFreak

+0

Ho aggiunto la spiegazione come risposta poiché non si adatta al commento. – Maroun

risposta

17

De Morgan's laws stato che:

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

l'applicazione di questa legge sulla sulla sua condizione:

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

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

Ora è più facile capire perché è sbagliato.

Se newAnswer è qualcosa che non è "Sì" o "sì", verrà valutato come true e non è ciò che si desidera.

La soluzione cambierebbe || in &&.

+0

La mia logica è davvero pessima, mi vergogno di me stesso. Come pratico la mia logica? – airsoftFreak

+2

Non dovresti vergognarti. Questo è lo scopo di appoggiare e praticare. Continua a provare e a chiedere, questo è solo il modo di imparare. Sei sulla buona strada! Sto ancora facendo degli stupidi errori anche dopo 5 anni di programmazione. – Maroun

+0

"Come pratico la mia logica?" Praticando la logica. L'esperienza fa il lavoro. Se può essere d'aiuto, pensa a && come "e allo stesso tempo ...". Vuoi che il ciclo si interrompa quando il valore inserito è "allo stesso tempo" diverso da tutti quelli che hai inteso. È come dire "almeno" (l'opposto di "allo stesso tempo") uguale (l'opposto di "diverso") –

6

Pensaci. Ti faccio una domanda si o no. Mi dici "no".

Vado giù la mia lista, e si ferma così presto come ottengo una vera affermazione, perché questo è ciò che OR logico significa.

newAnswer! = "Sì" >> vero. Fatto. Continua il ciclo.

Bene, si dice. Questa volta, rispondi "Sì".

newAnswer! = "Yes" >> falsa

newAnswer! = "Altro" >> vero. Fatto. Continua il ciclo.

Questa è una tautologia. Non è possibile rendere falsa quella condizione OR. Dovresti usare AND.

Con parole tue, non è "mentre non sì o no", ma "pur non sì E non no e non ne non y ..."

1

La logica è la seguente:

Se la stringa di input è un yes:

newAnswer != "yes" --> false 

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

La logica or di diversi true s ed uno false è un true. Ciò significa che per un ingresso di un ingresso yes, il ciclo continuerà. Se si modificano tutti i valori da or a and s, il numero logico and di diversi true s e uno false sarà false. Se l'ingresso è un ingresso yes, il ciclo non continuerà.

2

A parte l'inversione evidente tra & & e || tutte le risposte parlano, lasciami andare un po 'oltre, per rendere evidente un altro errore (non proprio un bug, ma una debolezza progettuale): chiedi "sì o no" accetta qualsiasi cosa e se la risposta sembra "si" tu Uscita. Qualcos'altro gioca come un no. Anche "una tazza di caffè".

E l'inversione di tutta la logica ha lo stesso errore: controllare per N, n, No, no per decidere di non uscire significa uscire se "tè e biscotti" hanno una risposta.

Inoltre, getAnswer prende rispondere alle chiamate e chooseOptions (che a sua volta ottenere qualche input per dare a getAnswer): non stai Looping: sei recoursing. E stai facendo la stessa cosa (ottieni una risposta da un input) da due posti diversi. Cosa succede se voglio cambiare std::cin con un altro flusso? Tutto da cambiare? In quanti posti diversi?

Una logica molto migliore dovrebbe forzare la risposta ad essere coerente.

Nel programma principale che si dovrebbe fare molto probabilmente qualcosa di simile

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

O, più conciso,

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 
} 

Ora, consente di entrare nella logica risposta:

Devi ottieni una riga di input (non una sola parola: una riga, dato che posso digitare "sì, voglio"), quindi cin>>string non gioca bene: meglio std::get_line. Se è "sì", restituisce true, se "no" restituisce false e se non altro ripete la lettura.

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

Questo consente di accettare le varianti "sì o no", ma rifiuta qualsiasi altra cosa.

Andando ancora oltre, possiamo rendere l'idea che cin/cout può essere un altro tipo di streaming e potrebbe non esserci nessuno che "digiti".

Per evitare di andare in un loop infinito, siamo in grado di introdurre un limite di tentativo e un'eccezione se si raggiunge:

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

e lasciare che il chiamante per la cattura alla fine e fare qualche altra azione, o eventualmente terminare con grazia.

Inoltre, possiamo parametrizzare non solo l'I/O e le domande, ma anche le risposte, ma questo sta andando troppo lontano.

Problemi correlati