49 votes

Utilisation de getline(cin, s) après cin

J'ai besoin du programme suivant pour prendre la ligne entière d'entrée de l'utilisateur et la mettre dans des noms de chaîne :

cout << "Enter the number: ";
int number;
cin >> number;

cout << "Enter names: ";
string names;

getline(cin, names);

Avec le cin >> number avant la commande getline() (ce qui, je suppose, est le problème), il ne me permet pas d'entrer des noms. Pourquoi ?

J'ai entendu quelque chose à propos d'un cin.clear() mais je n'ai aucune idée de la manière dont cela fonctionne ou de la raison pour laquelle cela est nécessaire.

26voto

Cristiano Miranda Points 259
cout << "Enter the number: ";
int number;
cin >> number;

cin.ignore(256, '\n'); // remaining input characters up to the next newline character
                       // are ignored

cout << "Enter names: ";
string names;
getline(cin, names);

20voto

jonsca Points 6571

Une autre façon de procéder est de mettre un

cin.ignore ( std::numeric_limits<std::streamsize>::max(), '\n' ); 

après votre cin>>number; pour vider complètement le tampon d'entrée (en rejetant tous les caractères supplémentaires jusqu'à ce qu'une nouvelle ligne soit trouvée). Vous devez #include <limits> pour obtenir le max() méthode.

11voto

Tony D Points 43962
cout << "Enter the number: ";
int number;
if (cin >> number)
{
    // throw away the rest of the line 
    char c;
    while (cin.get(c) && c != '\n')
        if (!std::isspace(c))
        {
            std::cerr << "ERROR unexpected character '" << c << "' found\n";
            exit(EXIT_FAILURE);
        }
    cout << "Enter names: ";
    string name;
    // keep getting lines until EOF (or "bad" e.g. error reading redirected file)...
    while (getline(cin, name))
        ...use name...
}
else
{
    std::cerr << "ERROR reading number\n";
    exit(EXIT_FAILURE);
}

Dans le code ci-dessus, ce bit...

    char c;
    while (cin.get(c) && c != '\n')
        if (!std::isspace(c))
        {
            std::cerr << "ERROR unexpected character '" << c << "' found\n";
            exit(EXIT_FAILURE);
        }

...vérifie que le reste de la ligne d'entrée après le numéro ne contient que des espaces.

Pourquoi ne pas simplement utiliser "ignorer" ?

C'est assez verbeux, donc en utilisant ignore sur le flux après >> x est un moyen alternatif souvent recommandé pour supprimer le contenu jusqu'à la prochaine nouvelle ligne, mais il risque de supprimer le contenu qui n'est pas un espace blanc et, ce faisant, de négliger les données corrompues dans le fichier. Vous pouvez vous en préoccuper ou non, selon que le contenu du fichier est fiable ou non, qu'il est important d'éviter de traiter des données corrompues, etc.

Alors quand utiliseriez-vous clear et ignorez ?

Donc, std::cin.clear() (et std::cin.ignore() ) n'est pas nécessaire pour cela, mais est utile pour supprimer l'état d'erreur. Par exemple, si vous voulez donner à l'utilisateur plusieurs chances d'entrer un nombre valide.

int x;
while (std::cout << "Enter a number: " &&
       !(std::cin >> x))
{
    if (std::cin.eof())
    {
        std::cerr << "ERROR unexpected EOF\n";
        exit(EXIT_FAILURE);
    }

    std::cin.clear();  // clear bad/fail/eof flags

    // have to ignore non-numeric character that caused cin >> x to
    // fail or there's no chance of it working next time; for "cin" it's
    // common to remove the entire suspect line and re-prompt the user for
    // input.
    std::cin.ignore(std::numeric_limits<std::streamsize>::max());
}

Ne peut-on pas faire plus simple avec skipws ou autre ?

Une autre alternative simple mais peu convaincante à ignore pour votre exigence initiale est d'utiliser std::skipws pour sauter n'importe quelle quantité d'espace avant de lire les lignes...

if (std::cin >> number >> std::skipws)
{
    while (getline(std::cin, name))
        ...

...mais s'il reçoit une entrée comme "1E6" (par exemple, un scientifique essayant d'entrer 1 000 000 mais le C++ ne supporte que cette notation pour les nombres à virgule flottante) ne l'acceptera pas, vous vous retrouverez avec number réglé sur 1 y E6 lu comme la première valeur de name . Par ailleurs, si un numéro valide est suivi d'une ou plusieurs lignes vides, ces lignes sont ignorées en silence.

10voto

Loki Astari Points 116129

Essayez :

int number;

cin >> number;

char firstCharacterOfNames;
cin >> firstCharacterOfNames;  // This will discard all leading white space.
                               // including new-line if there happen to be any.

cin.unget();                   // Put back the first character of the name.

std::string  names;
std::getline(cin, names);      // Read the names;

Alternativement. Si vous savez que le numéro et les noms seront toujours sur des lignes différentes.

cin >> number;
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); 
std::getline(cin, names);

8voto

Rajeev Atmakuri Points 677

Vous pouvez utiliser std::ws pour extraire tous les caractères d'espacement dans le tampon d'entrée avant d'utiliser getline. L'en-tête de std::ws est sstream.

cout << "Enter the number: ";
int number;
cin >> number;
cout << "Enter names: ";
string names;
cin>>ws;
getline(cin, names);

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X