Problemi con l'istruzione cin

L'istruzione cin non sempre funziona nel migliore dei modi.
Per dimostrarlo ho pensato di fare un piccolo programma che riceve una stringa da tastiera e verifica se la stringa è uguale ad un codice numerico specifico.

Conoscete il telefilm Lost?
Nel caso non lo abbiate mai visto, parla di un gruppo di persone disperse in un'isola deserta.
Se avete intenzione di vederlo saltate pure la parte contrassegnata da SPOILER perché rivela delle parti del telefilm, altrimenti continuate a leggere.

INIZIO SPOILER

Senza stare a raccontare tutto, i dispersi scoprono un bunker, una stazione sotterranea appartenente ad un progetto di ricerca scientifica, all'interno della quale ci sono un computer ed un timer.
Ogni 108 minuti qualcuno deve inserire un codice numerico, altrimenti il timer raggiunge lo zero e succede qualcosa di molto brutto :)
Cosa c'entra tutto questo con la programmazione? Non molto a dir la verità, ma ho pensato di scrivere un piccolo esempio che utilizza le istruzioni che abbiamo imparato sino ad ora per verificare l'inserimento di quel codice, e simulare così il programma che gira su quel computer.
Il codice è: 4 8 15 16 23 42.

FINE SPOILER

Il programma accetta in input una stringa, dopodiché verifica se la stringa è uguale al codice 4 8 15 16 23 42.
Vediamo la versione con cin:

#include <iostream>
#include <string>

using namespace std;

int main()
{
int varTentativi = 0;

bool varEsci = false;

string varCodice;

while(varEsci == false)
{
cout << "INSERISCI I NUMERI: " << endl;
cin >> varCodice;

if(varCodice == "4 8 15 16 23 42")
{
cout << "NUMERI CORRETTI " << endl;
varEsci = true;
}
else
{
cout << "NUMERI ERRATI " << endl;
varTentativi = varTentativi + 1;
}

if(varTentativi < 5)
{
cout << "TENTATIVI ESEGUITI: " << varTentativi << endl;
}
else
{
cout << "ERRORE DI SISTEMA! " << endl;
varEsci = true;
}
}

return 0;
}

Il programma controlla se il codice inserito dall'utente è uguale alla stringa numerica che ho riportato poco fa.

Prima di tutto il ciclo while esegue il codice all'interno del suo blocco sinché varEsci è diversa da true.

La variabile varEsci è una variabile booleana, che all'inizio è impostata a false, mentre viene impostata a true in due casi: se l'utente inserisce il codice esatto o se l'utente inserisce il codice errato per più di 5 volte.
In entrambi i casi la variabile varEsci viene impostata a true, e al ciclo successivo, la condizione varEsci diversa da true non si verifica, quindi il programma esce dal ciclo.

Il primo if controlla se il codice è uguale a 4 8 15 16 23 42.
Se è uguale, mostra un messaggio di notifica ed imposta la variabile varEsci a true, in modo che al prossimo ciclo il programma esca dal blocco;
se invece non è uguale, e cioé l'utente ha inserito il codice errato, mostra un avviso e poi incrementa la variabile varTentativi di 1.

Il secondo if invece controlla quanti tentativi sono stati fatti.
Se i tentativi sono ancora meno di 5, si limita a stampare il numero di tentativi;
mentre se i tentativi sono 5 avverte l'utente che non ha più possibilità ed il sistema è in collasso, dopodiché imposta la variabile varEsci a true in modo che al ciclo successivo non venga eseguito il blocco di codice di while.

Provate a compilare il programma e ad eseguire il codice.
Quando vi viene chiesto, inserite un codice numerico errato e vedete cosa succede.
Come probabilmente avrete visto, il programma non passa al secondo tentativo, ma fa tutto da solo stampando una cosa del genere:

INSERISCI I NUMERI:
3 44 5h4u
NUMERI ERRATI
TENTATIVI EFFETTUATI: 1
INSERISCI I NUMERI: //dovrebbe fermarsi qui!
NUMERI ERRATI //non abbiamo inserito nessun numero!
TENTATIVI EFFETTUATI: 2
INSERISCI I NUMERI:
NUMERI ERRATI
TENTATIVI EFFETTUATI: 3

Come mai succede questo?
Succede perché l'istruzione cin non elimina il carattere "a capo" dallo streaming di input.
In altre parole, una volta inserito il codice e premuto invio, nello streaming di input resta memorizzato il carattere di ritorno a capo, e all'istruzione cin successiva, questa raccoglie il carattere di ritorno a capo ancora presente nello streaming di input, e lo interpreta come se l'utente avesse premuto il tasto invio.

Per evitare questo possiamo utilizzare la funzione getline al posto del cin.
La funzione getline si utilizza in questo modo:

getline(streaming, variabile);

Dove, nel nostro esempio, streaming è cin mentre variabile è varCodice.

Provate a sostituire

cin << varCodice;

con

getline(cin, varCodice);

e vedrete che tutto funzionerà come previsto.

Nessun commento:

Posta un commento