web-dev-qa-db-fra.com

Si les instructions dans une boucle Do While avec une fin Oui ou Non

Je suis nouveau dans le domaine du codage et j'essaie de créer une longue boucle do while avec des instructions if imbriquées, mais je ne parviens pas à mettre ma boucle en boucle. 

Au lieu d'obtenir de l'aide directement sur mon projet, qui a un code très long, j'ai créé une version assez simple. Il ne fait pas de boucle non plus. Il ira à la fin et demandera à l'utilisateur s'il souhaite réessayer mais lorsque "y" est entré, il ignore les instructions if. 

#include <iostream>
#include <string>
using namespace std;

int main()
{
    string sodaChoice;
    char answer = 'n';

    do
    {
        cout << "Please choose your favorite soda from the following: Rootbeer, Diet Coke, Coke, Sprite" << "\n";
        getline(cin, sodaChoice);

        if (sodaChoice == "Rootbeer")
        {
            cout << "Me too!" << "\n";
        }
        else if (sodaChoice == "Diet")
        {
            cout << "Not me :(" << "\n";
        }
        else if (sodaChoice == "Coke")
        {
            cout << "It's alright" << "\n";
        }
        else if (sodaChoice == "Sprite")
        {
            cout << "only if I'm sick" << "\n";

        }
        else
        {
            cout << "That was not on the list";
        }
        cout << "would you like to try again?";
        cin >> answer;



    } while (answer == 'y'|| answer == 'Y');




    return 0;
}

Je pensais que j'avais peut-être besoin d'une boucle dans la boucle autour des déclarations if, mais je ne savais pas comment s'y prendre. Toute aide serait appréciée. J'ai passé de nombreuses heures à essayer de comprendre. 

J'ai essayé de demander à mon professeur, mais mon collège enseigne à partir d'un programme générique que leur doyen a écrit sur la base de son livre. Il n'est pas très enthousiaste à l'idée d'aider ou d'enseigner. 

EDIT: Merci à tous pour les réponses! S'agissant d'une question en double, je n'avais pas encore appris cin.ignore. Je ne savais donc pas qu'elle était pertinente pour mon problème. Merci à tous de m'apprendre! 

15
JKisa

Avec

cin >> answer;

vous lisez exactement un caractère. Le problème est que vous avez entré au moins deux caractères lors de l'écriture de la réponse. Le 'y' ou 'n' plus le Enter key, qui est ajouté en tant que retour à la ligne dans le tampon d’entrée.

Cette nouvelle ligne est alors lue par le prochain appel getline comme une ligne vide.

Il existe plusieurs solutions à ce problème, par exemple, en utilisant ignore après avoir lu dans answer. Ou, si vous souhaitez uniquement des entrées d'un seul mot, vous pouvez également utiliser une entrée formatée utilisant >> pour sodaChoice également, car elle ignorera par défaut les espaces blancs (comme les nouvelles lignes).

13

Les réponses existantes sont correctes dans le cas où l'utilisateur se comporte bien et n'entre qu'un "y" ou un "n" suivi d'une nouvelle ligne. 

Nous pouvons ajouter un peu de sécurité en modifiant l’appel .ignore () en lui demandant d’ignorer tous les caractères jusqu’à la nouvelle ligne suivante:

Vous devrez ajouter cet en-tête, inclure en haut de votre unité de traduction:

#include <limits>

Et vous devrez ajouter cette ligne avant cin >> answer:

// consumes and ignores as many characters as necessary until a newline. 
// The newline is also consumed.
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

Programme complet avec entrées de test ici:

http://coliru.stacked-crooked.com/a/996e77559590ad6d

Malheureusement, il n’est pas rare que les professeurs d’informatique n’ignorent rien à l’informatique. Ne vous inquiétez pas pour cela et ne vous laissez pas décourager par l'apprentissage de la rédaction de logiciels. Ce n'est qu'un symptôme du fait que les bons ingénieurs logiciels sont payés beaucoup plus que les bons enseignants.

Voici quelques documents de référence utiles: https://en.cppreference.com/w/cpp/io/basic_istream/ignore

7
Richard Hodges

Je vais suggérer quelque chose de complètement à l'opposé des autres réponses. Au lieu d'utiliser cin.ignore pour ignorer les caractères supplémentaires après celui que vous avez lu, je pense qu'il est préférable de faire toute votre lecture avec getline() et d'oublier complètement le cin >> somevar.

Il y a deux raisons:

  1. L'entrée formatée que vous obtenez avec cin >> somevar ignore les grands espaces, y compris les nouvelles lignes. Si l'utilisateur clique Enter sur une ligne vide, le programme ne fait rien, mais attend toujours d'autres entrées. Ce n'est pas ce que l'utilisateur d'un programme CLI attend! L'attente habituelle est que Enter termine l'entrée, et une entrée vide devrait inciter le programme à utiliser une valeur par défaut ou se plaindre d'une entrée non valide. Avec cin >> somevar, vous ne pouvez pas faire non plus.

  2. L'entrée formatée laisse toute entrée non appariée dans la mémoire tampon. Dans votre exemple, la lecture d'un seul caractère laisse au moins la nouvelle ligne suivante, mais il en va de même avec d'autres types d'entrée. La lecture d'un numéro (avec int i; cin >> i;) laisse rien après le nombre en attente de la prochaine opération d'entrée. La saisie de 123 abc retournera donc 123 et le abc apparaîtra lors de la prochaine opération d'entrée.

    La cause sous-jacente est que, par défaut, un terminal de ligne de commande est en mode ligne. Le programme ou les fonctions de la bibliothèque ne voient aucune entrée du système d'exploitation tant qu'une ligne complète n'est pas entrée. (cin.ignore() peut bien sûr vous aider à gérer cela, mais pas au premier point.)

Utiliser getline() correspond exactement au mécanisme sous-jacent, vous permet de traiter les entrées vides (ainsi que de faire la différence entre un zéro et un non-nombre lors de la lecture d'un int), et de traiter automatiquement les déchets à la fin. Vous devrez cependant convertir la chaîne de lecture manuellement en tout ce que vous voulez réellement.

Dans votre cas, vous pouvez changer la condition de boucle trivialement comme suit:

string answer;
...
    getline(cin, answer);
} while (answer == "y" || answer == "Y");

Si vous avez besoin d’un numéro, vous pouvez utiliser par exemple int num = std::stoi(str).


(En C, la même chose se produit si vous utilisez scanf() pour la saisie de l'utilisateur. Il est également préférable d'utiliser fgets(), puis d'analyser la chaîne avec sscanf(), qui donne les mêmes options mais traite de la mise en mémoire tampon des lignes. Je ne connais pas trop C++. , donc je ne peux pas dire comment avoir l’équivalent exact de cin >> somevar avec une ligne complète lue par getline().)

5
ilkkachu

Étant donné que vous prenez des entrées de l'utilisateur de type char mais que chaque touche Enter est touchée, il affecte la nouvelle ligne (\n) à la variable answer.

Vous pouvez l'ignorer en ajoutant une ligne juste après la ligne d'entrée

cin.ignore();

Vous pouvez lire ceci pour plus de détails.

0
Shravan40