Forcer l'entré d'un int par l'utilisateur C++

Résolu/Fermé
Lanthane - Modifié par Lanthane le 25/01/2012 à 11:06
 Lanthane - 27 janv. 2012 à 11:35
Bonjour,

Étant débutant en programmation je me suis occupé a créer un programme simple de calcul d'heure. En gros en fonction d'une heure d'arrivé cela renvoi une heure de sortie en ajoutant une durée prédéterminée.

Tout marche nickel SAUF un petit détails dont je ne comprend pas l'origine (rendant difficile toute recherche pour résoudre mon problème).

Je demande à l'utilisateur d'entrer une valeur type int (nombre d'heures ou de minutes) afin de faire les calculs nécessaires. Cela marche tant que l'utilisateur rentre bien un nombre entier.
CEPENDANT si l'utilisateur entre un autre caractère (comme une lettre), mon programme plante complétement...

Comment dois je procéder? Je pensais forcer l'entrée d'un int mais comment? Existe t il une solution mieux adaptée?

Je vous envoie la partie de mon code qui pause problème afin de mieux comprendre.
Merci de votre aide.

#include <iostream>     
using namespace std;     

bool valideHeure (int heure)     
    {return (heure>= 7 && heure<= 19); }     

bool valideMinute (int minute)     
    {return (minute>= 0 && minute<= 60); }     


int main()     
{     
  int hArrivee;     
  int mArrivee;     

        do     
        {     
        cout << endl << endl << "Indiquer l'heure d'arrivee en heure (sans les minutes) : ";     
            cin >> hArrivee;     
        } while (!valideHeure (hArrivee));     

        do     
        {     
        cout << endl << "Indiquer les minutes de votre heure d'arrivee : ";     
            cin >> mArrivee;     
        } while (!valideMinute (mArrivee));     

    cout << endl << "Vous etes arrivee a : " << hArrivee << "h" << mArrivee << endl;     

    return 0;     
}     
A voir également:

23 réponses

matthoffman Messages postés 405 Date d'inscription lundi 24 mars 2008 Statut Membre Dernière intervention 22 janvier 2013 47
26 janv. 2012 à 15:54
Voici le code:

 if (!(cin >> hArrivee))
          {
          cerr << "Merci d'entrer un entier valide" << endl;
          cin.clear();
          cin.ignore(1);
        }


NB: Pense a initialiser ta variable hArrivee de maniere a ce que tu puisses refaire un tour de boucle
9
matthoffman Messages postés 405 Date d'inscription lundi 24 mars 2008 Statut Membre Dernière intervention 22 janvier 2013 47
26 janv. 2012 à 16:11
De rien :).

"edit: juste un petit détails! si j'entre plusieurs lettre a la suite, le message d'erreur se répéte. En gros si j'entre 3 lettre j'aurais 3 messages d'erreurs."

Oui desole c'est a cause du ignore ^^:
cin.ignore(numeric_limits<streamsize>::max(), '\n')


Voila.

"Donc en fait le problème venais simplement du fait que ma boucle gardé en mémoire ma variable? "

Si tu parles du probleme de boucle infini, non car avec le break tu sors de ta boucle de toute facon.
Si tu parles du fait que tu repassais sans cesse dans le message d'erreur alors oui c'etait ca le pb.
2
ZeRo0Cold Messages postés 10 Date d'inscription lundi 20 juin 2011 Statut Membre Dernière intervention 27 janvier 2012 1
27 janv. 2012 à 07:25
une fonction qui permet de forcer saisir un INT en C

int saisieInt(void)
{char s[20] , c ;
int k=0,h;

do{
do{ c=getch();
} while(!isdigit(c)&& c!=13&& c!=8);

if(isdigit(c))
{s[k]=c ;k++;putchar(c);}

if(c==8&&k>0) {putchar(8);putchar(' ');putchar(8);k--;}

}while(c!=13);

s[k]='\0';
printf("\n");

h=atoi(s);
return(h);
}

seulement traduire en C++

bn courage;
2
Bonjour,

Il y aurait bien la fonction atoi() pour résoudre ton problème.
Il faut prendre l'entrée utilisateur comme un char[] et la transformer en int.
mes sources:
http://www.cplusplus.com/reference/clibrary/cstdlib/atoi/

;)
1

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
matthoffman Messages postés 405 Date d'inscription lundi 24 mars 2008 Statut Membre Dernière intervention 22 janvier 2013 47
26 janv. 2012 à 14:39
Tant de reponse et aucune vraie solution.
atoi ne renvoie pas d'erreurs s'il y a des caracteres non numeriques, a mon souvenir.
isdigit check les caracteres pas la string en entier, donc si tu dois faire un parcours de chaine juste pour ca c'est quand meme vraiment moche.

Bref pour faire simple voici ce qui resoudra ton probleme:

  if (!(cin >> hArrivee))
    cerr << "Merci d'entrer un entier valide" << endl;
1
matthoffman Messages postés 405 Date d'inscription lundi 24 mars 2008 Statut Membre Dernière intervention 22 janvier 2013 47
Modifié par matthoffman le 26/01/2012 à 15:30
Le code que je t'ai donne verifie si on peut faire rentrer le contenu du stream cin dans un entier.

Si on ne peut pas alors on ecris sur la sortie d'erreur "Merci de blablabla...."

Bien sur ce code n'empeche en rien, d'executer ta condition de boucle:
valideHeure (hArrivee)
(qui du coup en cas d'erreur ne contient rien vu que cin >> hArrivee a ete un echec)

Donc apres le comportement de ton programme c'est a toi de savoir ce que tu fais en cas d'erreur.

Un exemple, si en cas d'erreur tu veux sortir de ta boucle alors tu ecris ca:

if (!(cin >> hArrivee))  
{ 
        cerr << "Merci d'entrer un entier valide" << endl;  
        break; 
}
1
Je croyais avoir compris mais apparemment pas...

Si j'entre une lettre j'ai toujours ce fichu problème, le programme s'emballe.

En gros j'aimerais que si l'utilisateur entre tout autre caractère qu'un entier, mon programme lui redemande l'entré d'une valeur. Éventuellement accompagné par un petit message d'erreur.

J'ai essayé d'appliquer ce que tu m'a dit comme ceci :

       do   
        {   
        cout << endl << endl << "Indiquer l'heure d'arrivee en heure (sans les minutes) : ";   
        if (!(cin >> hArrivee))   
        {cerr << "Merci d'entrer un entier valide" << endl;   
        break;}   
        } while (!valideHeure (hArrivee));   
1
matthoffman Messages postés 405 Date d'inscription lundi 24 mars 2008 Statut Membre Dernière intervention 22 janvier 2013 47
26 janv. 2012 à 15:52
Avec ce code la, si l'utilisateur rentre quelque chose qui n'est pas entier alors je t'assure que tu sors de ta boucle.
Je te fais un code pour gerer ton erreur comme tu le souhaites.
0
Bha j'ai du faire une bêtise quelque part car je ne sort jamais de ma boucle ^^.
Merci pour l'écriture du code a venir cela me permettra j'espère de comprendre mes erreurs.
0
matthoffman Messages postés 405 Date d'inscription lundi 24 mars 2008 Statut Membre Dernière intervention 22 janvier 2013 47
26 janv. 2012 à 15:57
Une petite precision:

es tu conscient que tu as 2 boucles dans ton programme ?
As tu bien integrer ces lignes dans tes 2 boucles ?
0
Oui je suis conscient d'avoir 2 boucles! J'ai effectué mes tests uniquement sur la 1ere d'entre elles.

A vrai dire ton code me servira pour 4 boucles dans l'ensemble de mon programme. j'ai simplement posté la petite partie de mon programme qui avais un problème. En realité celui ci est beaucoup plus complet que ces quelques lignes ^^
0
wahou merci a toi matthoffman ca marche ENFIN!

Donc en fait le problème venais simplement du fait que ma boucle gardé en mémoire ma variable?

edit: juste un petit détails! si j'entre plusieurs lettre a la suite, le message d'erreur se répéte. En gros si j'entre 3 lettre j'aurais 3 messages d'erreurs.
Je supose que je doit simplement mettre un nombre plus elevé dans cin.ignore(1)?
1
D'accord merci beaucoup. C'était rageant d'être bloqué sur un tel détail. Détail qui rendait mon programme vraiment bancal ^^

La j'ai mi le chiffre 10 dans cin.ignore. Mais est t'il possible de mettre quelque chose qui dise cin.ignore (nombre infini)?

C'est peu utile je l'accorde car je doute que quelqu'un s'amuse a entrer un grand nombre de chiffre...

Merci bien a tous ceux qui ont pris la peine de me répondre et plus particulièrement a matthoffman pour cette solution simple mais efficace ainsi que tes explications.

edit : je commence a croire que je suis plutôt du genre chiant!
j'ai fait un test en tapant 8h (erreur qui sera je pense courante).

le programme de demande donc d'entrée mes minutes (donc la suite du programme) puis affiche le message d'erreur (des minutes et non des heures).

Voici mon code avec les modification apportées.

#include <iostream>
using namespace std;

bool valideHeure (int heure)
    {return (heure>= 7 && heure<= 19); }

bool valideMinute (int minute)
    {return (minute>= 0 && minute<= 59); }


int main()
{
  int hArrivee;
  int mArrivee;


do
        {
        cout << endl << endl << "Indiquer l'heure d'arrivee (sans les minutes) : ";
        if (!(cin >> hArrivee))
          {
          cerr << "Merci d'entrer un chiffre entre 7 et 19" << endl;
          cin.clear();
          cin.ignore(10);
        } }while (!valideHeure (hArrivee));


        do
        {
        cout << endl << "Indiquer les minutes de votre heure d'arrivee : ";
        if (!(cin >> mArrivee))
          {
          cerr << "Merci d'entrer un chiffre entre 0 et 59" << endl;
          cin.clear();
          cin.ignore(10);
        }} while (!valideMinute (mArrivee));

    cout << endl << "Vous etes arrivee a : " << hArrivee << "h" << mArrivee << endl;

    return 0;
}

1
matthoffman Messages postés 405 Date d'inscription lundi 24 mars 2008 Statut Membre Dernière intervention 22 janvier 2013 47
26 janv. 2012 à 16:22
Pour le ignore je t'ai donne la solution dans mon message precedent ^^.

Justement non il ne faut pas que tu specifies un nombre particulier de caracteres.

Regle premiere en programmation: ne jamais faire confiance a l'utilisateur.
0
Oui ca je sait ^^ quand je vois des amis ou collègues qui utilise des logiciels j'ai peur ^^

je suppose que tu parle de :
cin.ignore(numeric_limits<streamsize>::max(), '\n')

je ne suis pas encore familiarisé avec cette notation :s! A tu un petit indice stp? ^^
et pour le fait que j'ai les deux messages d'erreur quand j'entre 8h par ex?
0
matthoffman Messages postés 405 Date d'inscription lundi 24 mars 2008 Statut Membre Dernière intervention 22 janvier 2013 47
26 janv. 2012 à 16:52
Ok alors la fonction ignore(n, char) comme tu l'aura compris ignore les prochains n caractere, OU ignore jusqu'a ce qu'il rencontre le caractere char.

numeric_limits<streamsize>::max() fait partie de la STL. Comme son nom l'indique cela represente la limite numerique maximale que tu peux faire rentrer dans un stream.

Pour le 8h c'est normal, en fait cin fait rentrer le 8 dans ta variable, et vu que le h il peut pas le foutre dans un int, du coup il s'arrete avant le h.
Donc tes heures valent 8 ce qui est correct donc tu continues dans ton programme.
Ensuite tu continues mais ton cin n'est pas vide vu qu'il reste ce fameux "h" et le "\n", donc tu n'attends pas l'utilisateur vu que tu as encore quelque chose dans ton cin.
Donc tu le remplis pour les minutes, et vu que tu peux pas faire rentrer "h" dans un int, tu as l'erreur pour les minutes.

Essaye de trouver un moyen pour contourner ce probleme, ou peut etre un autre membre t'aidera, mais la je dois partir, donc je ne pourrais revenir que ce soir pour t'aider.
0
d'accord! Donc en gros il faudrait que je "vide" la mémoire une fois que je rencontre un char...
Merci bien, je vais planché sur le sujet dans la soirée! Si je trouve je l'indiquerais, dans le cas contraire ton aide sera la bienvenue.

Merci beaucoup j'ai déjà compris beaucoup de chose avec tes explications.
0
Bon et bien je cherche, je cherche, mais je ne vois vraiment pas comment ignoré ou "vidé" le reste de mon cin...
0
Pk la moitié du sujet a été supprimé? :s

Bon bha petit rappel j'en été la:

do
        {
        cout << endl << endl << "Indiquer l'heure d'arrivee (sans les minutes) : ";
        if (!(cin >> hArrivee))
          {
          cerr << "Merci d'entrer un chiffre entre 7 et 19" << endl;
          cin.clear();
          cin.ignore (numeric_limits<streamsize>::max(), '\n');
        } }while (!valideHeure (hArrivee));


Et j'avais le souci que si j'entré 8h, j'avais un message d'erreur avant d'avoir la demande pour la suite du programme...

Mattfoffman m'a deja beaucoup aidé! Mais je n'arrive pas a "vidé" mon cin pour évité les erreurs!
1
matthoffman Messages postés 405 Date d'inscription lundi 24 mars 2008 Statut Membre Dernière intervention 22 janvier 2013 47
27 janv. 2012 à 01:37
Désolé pour la réponse tardive. Les messages n'ont pas disparus, ils ont juste été "uppés". regarde plus haut dans le topic ;).

Pour ton programme si je me souviens bien, tu veux que 8h soit reconnu comme une erreur, et non pas que le 8 soit sauvergardé et on s'en fout du reste.

Donc voici ce que je te propose:

 if (!(cin >> hArrivee) || (cin.peek() != '\n'))
      {
        hArrivee = -1;
        cerr << "Merci d'entrer un chiffre entre 7 et 19" << endl;
        cin.clear();
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
      }


J'ai donc rajouté une vérification: cin.peek() qui te renvoie le prochain caractère présent dans ton stream. On vérifie donc si l'utilisateur a fait un retour a la ligne directement après son nombre.
J'ai rajouté une initialisation a -1 (pour que tu refasses un tour de boucle). En effet dans le cas ou l'utilisateur rentre "8h", comme je te l'avais dit cette aprem, ta variable se verra quand même attribué la valeur 8, et du coup tu sortiras de ta boucle et donc tu continueras ton programme comme si 8h n'était pas une erreur.

Voila tiens moi au courant :). Bonne nuit, et encore désolé de répondre que maintenant.
1
a oui en effet ^^! Perturbant ca... Tellement l'habitude d'aller directement en ba du sujet...

Pour la réponse tardive il n'y a aucun souci! Étant un projet personnel je n'ai pas de délai a tenir et chacun a sa vie tout de même ^^.

Je n'ai pas le temps de testé pour le moment mais je le ferais dans la journée.
merci beaucoup a toi, c'est agréable d'avoir de l'aide accompagné d'explication (afin de ne pas copié bêtement ce qu'on m'envoie)
0
choubaka Messages postés 39375 Date d'inscription jeudi 4 avril 2002 Statut Modérateur Dernière intervention 14 avril 2024 2 100
25 janv. 2012 à 10:43
bonjour

C'est ce qu'on appelle la gestion d'exception (erreurs).
Vous devez contrôler les valeurs entrées par l'utilisateur avant de les traiter.
Un simple test "If". si l'entrée est correcte, on continue le traitement sinon on demande à l'utilisateur d'entrer à nouveau les valeurs correctes.
0
D'accord je pensé que mon booleen suffisait à définir cette exception.
Par contre créer un test "if" n'est pas un problème mais comment dire au programme :

"Si a n'est pas un int" ?

Je doit simplement remplacer mon booleen par un if effectuant la meme verification?

edit: Je vien de creer ce test IF est j'ai toujorus le meme probleme :s

int valideHeure2 (int heure) 
{ 
    if (heure>= 7 && heure<= 19) 
    { 
        return heure; 
    } 
    else 
    { 
    cout << endl << endl << "Indiquer l'heure d'arrivee en heure (sans les minutes) : "; 
    cin >> hArrivee; 
    valideHeure2 (hArrivee); 
    } 
    return 0; 
} 

int main() 
{ 
  int hArrivee; 

    cout << endl << endl << "Indiquer l'heure d'arrivee en heure (sans les minutes) : "; 
    cin >> hArrivee; 
    valideHeure2 (hArrivee); 

return 0; 
} 
0
choubaka Messages postés 39375 Date d'inscription jeudi 4 avril 2002 Statut Modérateur Dernière intervention 14 avril 2024 2 100
25 janv. 2012 à 11:00
c'est du C++ ?
0
En effet j'ai oublié de préciser cette information capitale :s
j'ai édité le titre pour ajouter l'information ^^
0
choubaka Messages postés 39375 Date d'inscription jeudi 4 avril 2002 Statut Modérateur Dernière intervention 14 avril 2024 2 100
25 janv. 2012 à 11:15
je crois que tu dois utiliser isdigit
0
Bon soit j'ai mal utilisé isdigit, soit cela n'a pas résolu mon problème.
Déjà cela fonctionne bizarrement ^^.

Le programme me demande de nouveau d'entré mon heure d'arrivé jusqu'à 47 inclus. Au delà il a l'air de passer a l suite du programme!

Ensuite si je tape une lettre par exemple j'ai toujours le même problème! Le programme plante et lance une boucle indefiniment!


J'ai modifié mon If comme ci dessous :

int valideHeure2 (int heure)
{
    if (isdigit(heure))
    {
        return heure;
    }
    else
    {
    int hArrivee;
    cout << endl << endl << "Indiquer l'heure d'arrivee en heure (sans les minutes) : ";
    cin >> hArrivee;
    valideHeure2 (hArrivee);
    }
    return 0;
}
0
Petit up si quelqu'un a une idée merci!
Merci tout de meme a choubaka pour avoir essayé de resoudre mon probleme.
0
Merci pour vos réponses!

La fonction atoi() me semble plutôt intéressante (même si c'est un peu tuer une mouche avec un canon).
Cependant si celle ci renvoi 0 lorsqu'on n'entre pas un entier, alors cela rentre dans mes conditions pour la demande des minutes... Donc si l'utilisateur entre une lettre et non un entier (pour les minutes), au lieu d'une erreur, le programme prendra la valeur 0... C'est mieux qu'un plantage mais ce n'est pas propre non plus!


Matthoffman, je n'ai pas vraiment compris comment utiliser tes lignes de code (a quel endroit exact par ex etc)

Peut tu me l'expliquer afin que je puisse éventuellement le réutiliser dans d'autres programmes?

Merci bien

je l'ai inséré comme ci dessous mais j'ai toujours un plantage lorsque que j'entre une lettre! Est moi qui ai mal utilisé ta fonction?
Mise à part ce problème avec l'entrée d'entiers cela marche toujours!

        do     
        {     
        cout << endl << endl << "Indiquer l'heure d'arrivee en heure (sans les minutes) : ";     
        if (!(cin >> hArrivee))     
        cerr << "Merci d'entrer un entier valide" << endl;     
        } while (!valideHeure (hArrivee));     
0
vordano Messages postés 1682 Date d'inscription mardi 12 juillet 2011 Statut Membre Dernière intervention 20 juillet 2012 316
26 janv. 2012 à 15:46
bonjour,

pour vérifier le caractère, tu peux te baser sur son code ascii -> http://table-ascii.com/

pour info tu t'es trompé dans ton test sur les minutes :)
(minute>= 0 && minute<= 60) //ici tu as un total de 61 minutes, et la minute 0 et la 60 est la même minute
devrais être
(minute>= 0 && minute< 60)
0
Oui merci pour ce commentaire ^^! Je l'avais remarqué par la suite et j'ai modifié en 59 ^^.
0