cin et les erreurs

Dans une application console, c’est l’objet cin qui est utilisé pour saisir une valeur au clavier. La valeur saisie est envoyée au moyen de l’opérateur de flux entrant (>>) vers la variable qui recevra la saisie clavier. Le type de la variable déterminera le type de donnée à saisir au clavier.

// Saisie d’un nombre entier
int NombreEntier = 0;
std::cin >> NombreEntier;

// Saisie d’un nombre réel
float NombreReel = 0.;
std::cin >> NombreReel;

// Saisie d’un caractère
char Caractere = 0;
std::cin >> Caractere;

Si l’utilisateur saisi autre chose que ce qui est attendu, cin passe en état d’échec.

Cela signifie que si l’utilisateur saisi une lettre alors que c’est un nombre entier qui est attendu, cin se met en état d’échec (failed state). Voici un exemple très simple qui démontre le problème :

#include <iostream>

int main() {
   int Nombre1 = 12345;
   int Nombre2 = 999;

   std::cout << "Entrez un premier nombre entier : ";
   std::cin >> Nombre1;
   std::cout << "Entrez un second nombre entier : ";
   std::cin >> Nombre2;

   std::cout << "Vous avez saisi les nombres " << Nombre1
             << " et " << Nombre2 << "\n";
   return 0;
}

Si ce qui est saisi ne ressemble pas à un nombre entier, le flux cin passe en état d’échec (ligne 8 ) et toutes les demandes de saisie ultérieures (ligne 10) rendront immédiatement la main au programme sans que rien ne se passe.

Si l’appel à cin est fait au sein d’une boucle (par exemple pour vérifier si le nombre saisi est compris dans un intervalle donné) et que cin passe en état d’échec, le programme tournera en boucle infinie.

#include <iostream>

int main() {
   int Nombre = 0;

   while (true) {
      std::cout << "Entrez un nombre compris entre 1 et 100 : ";
      std::cin >> Nombre;
      if ((Nombre >= 1) && (Nombre <= 100))
         break;
   }
   std::cout << "Vous avez saisi le nombre " << Nombre << "\n";
   return 0;
}

Pour éviter ce problème, il faut tester la valeur de retour du flux cin. Si celle-ci est fausse, c’est qu’une erreur s’est produite et que cin est en état d’échec. Il faut alors rétablir le flux cin en purgeant tout ce qu’il contient.

#include <iostream>
#include <limits>

int main() {
   int Nombre = 0;

   while (true) {
      std::cout << "Entrez un nombre compris entre 1 et 100 : ";
      if (!(std::cin >> Nombre)) {
         // Purge du flux cin
         std::cin.clear();
         std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
      }

      if ((Nombre >= 1) && (Nombre <= 100))
         break;
   }
   std::cout << "Vous avez saisi le nombre " << Nombre << "\n";
   return 0;
}

Voici l’exemple précédent réécrit pour tenir compte de saisies erronées. Les lignes 11 et 12 se chargent de purger le flux cin et de le remettre dans un état valide.

Bien sûr, il serait malvenu d’écrire tout ce code supplémentaire chaque fois que le flux cin est utilisé. Pour éviter ces répétitions, il suffit d’écrire une fonction de saisie d’un nombre entier, qui se charge de traiter l’état d’erreur du flux cin.

Selon les besoins, cette fonction pourra être plus ou moins complexe. Voici une version minimale :

// Fonction de saisie d'un nombre entier au clavier
//@return le nombre entier saisi, ou zéro en cas de saisie invalide.
int getInteger() {
   int Nombre = 0;
   if (!(std::cin >> Nombre)) {
      // Purge du flux cin
      std::cin.clear();
      std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
   }
   return Nombre;
}

Voici le premier programme de cette annexe réécrit de façon à utiliser la fonction ci-dessus :

#include <iostream>
#include <limits>

// Fonction de saisie d'un nombre entier au clavier
//@return le nombre entier saisi, ou zéro en cas de saisie invalide.
int getInteger() {
   int Nombre = 0;
   if (!(std::cin >> Nombre)) {
      // Purge du flux cin
      std::cin.clear();
      std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
   }
   return Nombre;
}

// Programme principal
int main() {
   int Nombre1 = 12345;
   int Nombre2 = 999;

   std::cout << "Entrez un premier nombre entier : ";
   Nombre1 = getInteger();
   std::cout << "Entrez un second nombre entier : ";
   Nombre2 = getInteger();

   std::cout << "Vous avez saisi les nombres " << Nombre1
             << " et " << Nombre2 << "\n";
   return 0;
}

Tags: ,

Comments are closed.