web-dev-qa-db-fra.com

Comment gérer une entrée de type de données incorrecte

En C++, comment gérez-vous les mauvaises entrées? Par exemple, si le programme demande un entier, lorsque vous tapez un caractère, il devrait être capable de faire quelque chose, puis de boucler pour répéter l'entrée, mais la boucle devient infinie lorsque vous entrez un caractère lorsqu'un entier est nécessaire et vice versa.

22
Zik

La raison pour laquelle le programme entre dans une boucle infinie est parce que le mauvais indicateur d'entrée de std::cin Est défini en raison de l'échec de l'entrée. La chose à faire est d'effacer cet indicateur et de supprimer la mauvaise entrée du tampon d'entrée.

//executes loop if the input fails (e.g., no characters were read)
while (std::cout << "Enter a number" && !(std::cin >> num)) {
    std::cin.clear(); //clear bad input flag
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); //discard input
    std::cout << "Invalid input; please re-enter.\n";
}

Voir la FAQ C++ pour cela, et d'autres exemples, y compris l'ajout d'un minimum et/ou d'un maximum dans la condition.

Une autre façon serait d'obtenir l'entrée sous forme de chaîne et de la convertir en un entier avec std::stoi Ou une autre méthode qui permet de vérifier la conversion.

44
chris

La réponse la plus votée couvre très bien la solution.

En plus de cette réponse, cela peut aider à visualiser un peu mieux ce qui se passe:

int main()

    int input = 1;//set to 1 for illustrative purposes
    bool cinState = false;
    string test = "\0";
    while(input != -1){//enter -1 to exit
        cout << "Please input (a) character(s): ";//input a character here as a test
        cin >> input; //attempting to input a character to an int variable will cause cin to fail
        cout << "input: " << input << endl;//input has changed from 1 to 0
        cinState = cin;//cin is in bad state, returns false
        cout << "cinState: " << cinState << endl;
        cin.clear();//bad state flag cleared
        cinState = cin;//cin now returns true and will input to a variable
        cout << "cinState: " << cinState << endl;
        cout << "Please enter character(s): ";
        cin >> test;//remaining text in buffer is dumped here. cin will not pause if there is any text left in the buffer.
        cout << "test: " << test << endl;
    }
    return 0;    
}

Vider le texte du tampon dans une variable n'est pas particulièrement utile, mais cela aide à visualiser pourquoi cin.ignore() est nécessaire.

J'ai également noté la modification de la variable d'entrée, car si vous utilisez une variable d'entrée dans votre condition pour une boucle while, ou une instruction switch, elle peut se retrouver dans un blocage ou remplir une condition que vous n'étiez pas 't attend, ce qui peut être plus déroutant à déboguer.

6
AWolfAtTheDoor