OVH Cloud OVH Cloud

Newbie: vidage du tampon (cin)

12 réponses
Avatar
Dudule
Hello,

Afin d'effectuer une minuscule routine de saisie de donnés sur le prompt
(je suis en phase d'apprentissage), j'utilise un while avec une condition
de garde. Je teste ensuite la validité des valeurs entrées avec un switch.
Dans le default, je mets un message d'erreur, et je relance la saisie des
données.
Le problème est que lorsque je suis tombé dans le cas du default, je ne peux
plus rentrer de données, et ça boucle à l'infini. Je suppose que c'est lié
au vidage du tampon. Je n'ai pas ce problème avec les autre cases,

Merci pour votre aide.

        cout << "Saisissez les commandes sous la forme:   référence  quantité <<
endl;
        cout << "Entrez 0 0 pour terminer." <<  endl << endl;
        
        cout << "Produit (1-5) / Quantité: ";
        cin >> reference >> quantity;
        
        while (reference !=0 && quantity !=0)
        {
                switch (reference)
                {
                        case 1: quantity1 += quantity;
                                        break;
                        case 2: quantity1 += quantity;
                                        break;
                        case 3: quantity1 += quantity;
                                        break;
                        case 4: quantity1 += quantity;
                                        break;
                        case 5: quantity1 += quantity;
                                        break;
                        default:cout << "Erreur sur la saisie de la référence !" <<
endl << endl;
                                        break;
                }
                cout << "Produit (1-5) / Quantité: ";
                cin >> reference >> quantity;
        }

10 réponses

1 2
Avatar
Alexandre
bonjour,

<snip>

cout << "Saisissez les commandes sous la forme: référence quantité <<
endl;
cout << "Entrez 0 0 pour terminer." << endl << endl;

cout << "Produit (1-5) / Quantité: ";
cin >> reference >> quantity;

while (reference !=0 && quantity !=0)
{
switch (reference)
{
case 1: quantity1 += quantity;
break;
case 2: quantity1 += quantity;
break;
case 3: quantity1 += quantity;
break;
case 4: quantity1 += quantity;
break;
case 5: quantity1 += quantity;
break;
default:cout << "Erreur sur la saisie de la référence !" <<
endl << endl;
break;
}


ton switch ne sert pas à grand chose, puisque les actions sont toutes
similaires...
Tu peux remplacer l'ensemble par ceci, qui réalise le contrôle souhaité sans
boucle infinie :

do
{
cout << "Saisissez les commandes sous la forme: référence quantité << endl;
cout << "Entrez 0 0 pour terminer." << endl << endl;
cout << "Produit (1-5) / Quantité: ";
cin >> reference >> quantity;

}
while (reference >=1 && reference <=5 && quantity >0);
quantity1 += quantity;

Avatar
Oodini
bonjour,

<snip>

cout << "Saisissez les commandes sous la forme: référence quantité <<
endl;
cout << "Entrez 0 0 pour terminer." << endl << endl;

cout << "Produit (1-5) / Quantité: ";
cin >> reference >> quantity;

while (reference !=0 && quantity !=0)
{
switch (reference)
{
case 1: quantity1 += quantity;
break;
case 2: quantity1 += quantity;
break;
case 3: quantity1 += quantity;
break;
case 4: quantity1 += quantity;
break;
case 5: quantity1 += quantity;
break;
default:cout << "Erreur sur la saisie de la référence !" <<
endl << endl;
break;
}



ton switch ne sert pas à grand chose, puisque les actions sont toutes
similaires...


C'est parce qu'il y a une erreur dans le code:

case 1: quantity1 += quantity;
break;
case 2: quantity2 += quantity;
break;
case 3: quantity3 += quantity;
break;
case 4: quantity4 += quantity;
break;
case 5: quantity5 += quantity;
break;

Je suis confus...

Mais cette erreur n'était pas dans mon code, et la boucle infinie est
toujours présente.


Avatar
Cyrille
Hello,

Afin d'effectuer une minuscule routine de saisie de donnés sur le prompt
(je suis en phase d'apprentissage), j'utilise un while avec une condition
de garde. Je teste ensuite la validité des valeurs entrées avec un switch.
Dans le default, je mets un message d'erreur, et je relance la saisie des
données.
Le problème est que lorsque je suis tombé dans le cas du default, je ne peux
plus rentrer de données, et ça boucle à l'infini. Je suppose que c'est lié
au vidage du tampon. Je n'ai pas ce problème avec les autre cases,


Bonjour.
Normalement, le problème n'est pas dans le fait d'être passé dans le
default. Qu'est-ce que vous tapez comme entrée quand ça commence à
tourner en boucle?

En particulier, si l'utilisateur de votre programme tape n'importe quoi,
comme "Allez les bleus", l'instruction "cin >> reference >> quantity;"
ne peut extraire ce qu'il lui faut et cin entre dans un état d'échec.
cin.fail() renvoye true et toute tentative de lire avec cin échoue ensuite.

Vous pouvez recommencer à lire cin en écrivant:
if (cin.fail())
{
// échec
cin.clear();
cin.ignore(numeric_limits<int>::max(), 'n');
}

La ligne cin.clear() efface l'état d'échec et permet de relire dans cin.
La ligne cin.ignore(...) évacue tout ce qui se trouvait sur la ligne
défectueuse.

--
win the yes need the no to win against the no!

Avatar
kanze
Cyrille wrote:

Afin d'effectuer une minuscule routine de saisie de donnés
sur le prompt (je suis en phase d'apprentissage), j'utilise
un while avec une condition de garde. Je teste ensuite la
validité des valeurs entrées avec un switch. Dans le
default, je mets un message d'erreur, et je relance la
saisie des données.
Le problème est que lorsque je suis tombé dans le cas du
default, je ne peux plus rentrer de données, et ça boucle à
l'infini. Je suppose que c'est lié au vidage du tampon. Je
n'ai pas ce problème avec les autre cases,


Normalement, le problème n'est pas dans le fait d'être passé
dans le default. Qu'est-ce que vous tapez comme entrée quand
ça commence à tourner en boucle?

En particulier, si l'utilisateur de votre programme tape
n'importe quoi, comme "Allez les bleus", l'instruction "cin >>
reference >> quantity;" ne peut extraire ce qu'il lui faut et
cin entre dans un état d'échec. cin.fail() renvoye true et
toute tentative de lire avec cin échoue ensuite.

Vous pouvez recommencer à lire cin en écrivant:
if (cin.fail())
{
// échec
cin.clear();
cin.ignore(numeric_limits<int>::max(), 'n');
}

La ligne cin.clear() efface l'état d'échec et permet de relire
dans cin. La ligne cin.ignore(...) évacue tout ce qui se
trouvait sur la ligne défectueuse.


Tout à fait. (Ça fait plaisir de voir une réponse correcte quand
il s'agit des iostream. C'est souvent l'exception.) J'ajouterai
que même dans le cas où les entrées sont correctes, on pourrait
vouloir utiliser l'cin.ignore pour s'assurer que la prochaine
entrée a lieu sur une nouvelle ligne (ce qui traite tout ce qui
pourrait suivre les deux valeurs sur la ligne comme
commentaire).

Aussi, et plus important, il faut qu'il teste la réussite des
entrées avant le switch. Parce que s'il y a erreur, les valeurs
précédantes ne seront pas modifiées, et il ne veut pas faire un
switch sur elles.

Finalement, aussi, s'il n'entre qu'une valeur, son code va
attendre la deuxième. S'il veut réelement que les deux valeurs
soient sur une seule ligne, il vaut mieux lire la ligne au moyen
de getline, puis utiliser istringstream pour en extraire les
valeurs. Dans ce cas-ci, il pourrait aussi réfuser des
non-blancs à la fin de la ligne (plutôt que de les ignorer) ;
son expression de lecture deviendrait alors :

std::string line ;
if ( ! std::getline( std::cin, line ) ) {
// Fin de fichier ...
reference = 0 ;
quantity = 0 ;
} else {
std::istringstream s( line ) ;
s >> reference >> quantity >> std::ws ;
if ( ! s || s.peek() != EOF ) {
// Erreur de format ...
} else {
// C'est bon (on met le switch ici)...
}
}

Dans son cas, je verrais bien ce code dans un boucle do...while
(avec la sortie de l'invitation aux entrées en tête de la
boucle).

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Avatar
Dudule
Alexandre wrote:

switch (reference)
{
case 1: quantity1 += quantity;
break;
case 2: quantity1 += quantity;
break;
case 3: quantity1 += quantity;
break;
case 4: quantity1 += quantity;
break;
case 5: quantity1 += quantity;
break;
default:cout << "Erreur sur la saisie de la référence !" <<
endl << endl;
break;
}


ton switch ne sert pas à grand chose, puisque les actions sont toutes
similaires...


Copier/coller malencontreux.
Le code en question contient bien des "cases" différents.


Avatar
Dudule
Tout d'abord, désolé de répondre si tardivement, mais j'étais parti en
vacances. :-)

Cyrille wrote:


Bonjour.
Normalement, le problème n'est pas dans le fait d'être passé dans le
default. Qu'est-ce que vous tapez comme entrée quand ça commence à
tourner en boucle?


Des lettres (alors que le cin attend des entiers).

En particulier, si l'utilisateur de votre programme tape n'importe quoi,
comme "Allez les bleus", l'instruction "cin >> reference >> quantity;"
ne peut extraire ce qu'il lui faut et cin entre dans un état d'échec.


C'est effectivement ce qui a l'air de se passer.

cin.fail() renvoye true et toute tentative de lire avec cin échoue
ensuite.

Vous pouvez recommencer à lire cin en écrivant:
if (cin.fail())
{
// échec
cin.clear();
cin.ignore(numeric_limits<int>::max(), 'n');
}


Si je rajoute le code ci-dessus, mais en omettant le cin.ignore, j'obtiens à
la compilation les messages d'erreur suivants:

ex05_14.cpp:50: error: stray '302' in program
ex05_14.cpp:50: error: stray '240' in program
ex05_14.cpp:50: error: stray '302' in program
ex05_14.cpp:50: error: stray '240' in program
ex05_14.cpp:50: error: stray '302' in program
ex05_14.cpp:50: error: stray '240' in program
ex05_14.cpp:50: error: stray '302' in program
ex05_14.cpp:50: error: stray '240' in program
ex05_14.cpp:50: error: stray '302' in program
ex05_14.cpp:50: error: stray '240' in program
ex05_14.cpp:50: error: stray '302' in program
ex05_14.cpp:50: error: stray '240' in program
ex05_14.cpp:50: error: stray '302' in program
ex05_14.cpp:50: error: stray '240' in program
ex05_14.cpp:50: error: stray '302' in program
ex05_14.cpp:50: error: stray '240' in program

Si je rajoute le cin.ignore, j'obtiens en outre:

ex05_14.cpp:53: error: `numeric_limits' undeclared (first use this function)
ex05_14.cpp:53: error: (Each undeclared identifier is reported only once for
each function it appears in.)
ex05_14.cpp:53: error: syntax error before `>' token
ex05_14.cpp:53: error: `::max' undeclared (first use here)
ex05_14.cpp:53: error: syntax error before `)' token


La ligne cin.clear() efface l'état d'échec et permet de relire dans cin.
La ligne cin.ignore(...) évacue tout ce qui se trouvait sur la ligne
défectueuse.


C'est curieux, j'aurais inversé l'ordre de ces deux instructions...

Merci tout de même pour votre aide.

Avatar
Dudule
wrote:


Aussi, et plus important, il faut qu'il teste la réussite des
entrées avant le switch. Parce que s'il y a erreur, les valeurs
précédantes ne seront pas modifiées, et il ne veut pas faire un
switch sur elles.


Ben je croyais que le cin.ignore servait justement à ignorer les entrées
précédentes (fausses) ?


Finalement, aussi, s'il n'entre qu'une valeur, son code va
attendre la deuxième. S'il veut réelement que les deux valeurs
soient sur une seule ligne, il vaut mieux lire la ligne au moyen
de getline, puis utiliser istringstream pour en extraire les
valeurs. Dans ce cas-ci, il pourrait aussi réfuser des
non-blancs à la fin de la ligne (plutôt que de les ignorer) ;
son expression de lecture deviendrait alors :


Suggestion intéressante sur laquelle je me pecnherai dès que sera résolu le
problème initial. :-)

Merci pour votre point de vue, que j'intégrerai dans mon programme.

Avatar
Cyrille
Tout d'abord, désolé de répondre si tardivement, mais j'étais parti en
vacances. :-)

Vous pouvez recommencer à lire cin en écrivant:
if (cin.fail())
{
// échec
cin.clear();
cin.ignore(numeric_limits<int>::max(), 'n');
}



Si je rajoute le code ci-dessus, mais en omettant le cin.ignore, j'obtiens à
la compilation les messages d'erreur suivants:

ex05_14.cpp:50: error: stray '302' in program
ex05_14.cpp:50: error: stray '240' in program
...


Houla... apparemment des caractères bizarres sont venus quand vous avez
fait un copier-coller à partir de votre lecteur de news. Tapez le à la
main, plutôt.

Si je rajoute le cin.ignore, j'obtiens en outre:

ex05_14.cpp:53: error: `numeric_limits' undeclared (first use this function)
ex05_14.cpp:53: error: (Each undeclared identifier is reported only once for
each function it appears in.)
ex05_14.cpp:53: error: syntax error before `>' token
ex05_14.cpp:53: error: `::max' undeclared (first use here)
ex05_14.cpp:53: error: syntax error before `)' token


Il faut inclure l'en-tête standard <limits> pour utiliser
std::numeric_limits.

La ligne cin.clear() efface l'état d'échec et permet de relire dans cin.
La ligne cin.ignore(...) évacue tout ce qui se trouvait sur la ligne
défectueuse.



C'est curieux, j'aurais inversé l'ordre de ces deux instructions...


Je crois qu'on ne peut tout simplement rien faire sur le flux tant que
cin.fail() renvoye true. Donc cin.clear() s'impose.

Merci tout de même pour votre aide.


De rien.

--
win the yes need the no to win against the no!


Avatar
kanze
Dudule wrote:
wrote:

Aussi, et plus important, il faut qu'il teste la réussite
des entrées avant le switch. Parce que s'il y a erreur, les
valeurs précédantes ne seront pas modifiées, et il ne veut
pas faire un switch sur elles.


Ben je croyais que le cin.ignore servait justement à ignorer
les entrées précédentes (fausses) ?


Oui, mais dans le code original, il n'y avait qu'un switch, avec
un cas « default » pour les erreurs éventuelles. Tout ce que je
voulais dire, c'est qu'il ne faut pas passer par le switch dans
le cas où on a detecté une erreur. Le traitement de l'erreur ne
peut donc pas se trouver dans le cas « default ».

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Avatar
Dudule
Cyrille wrote:

ex05_14.cpp:50: error: stray '302' in program
ex05_14.cpp:50: error: stray '240' in program
...


Houla... apparemment des caractères bizarres sont venus quand vous avez
fait un copier-coller à partir de votre lecteur de news. Tapez le à la
main, plutôt.


Effectivement. Vous devez avoir de la bouteille pour identifier ce genre
d'erreurs. :-)

Il faut inclure l'en-tête standard <limits> pour utiliser
std::numeric_limits.


OK, ça roule.

J'ai donc pondu le code suivant, et sorti le test du switch, comme indiqué
par l'autre contributeur, mais j'ai un petit soucis: les valeurs saisies
sont réaffichées.

Voici une sortie écran:

--------------------------------------------------------------------
Saisissez les commandes sous la forme: référence quantité
Entrez 0 0 pour terminer.

Produit (1-5) / Quantité: a b
Erreur sur la saisie de la référence !

Produit (1-5) / Quantité: 2 4
24Produit (1-5) / Quantité: 0 0
00 Produit Prix unitaire Quantité Montant total
Produit 1 $2.98 0 $ 0.00
Produit 2 $4.50 4 $11.92
Produit 3 $9.98 0 $ 0.00
Produit 4 $4.49 0 $ 0.00
Produit 5 $6.87 0 $ 0.00

--------------------------------------------------------------------

Le code est:
--------------------------------------------------------------------
cout << "Saisissez les commandes sous la forme: référence quantité" <<
endl;
cout << "Entrez 0 0 pour terminer." << endl << endl;

cout << "Produit (1-5) / Quantité: ";
cin >> reference >> quantity;

while (reference !=0 && quantity !=0)
{
if (cin.fail()==true)
{
cout << "Erreur sur la saisie de la référence !" << endl << endl;
cin.clear();
cin.ignore(std::numeric_limits<int>::max(),'n');
}
else
switch (reference)
{
case 1: quantity1 += quantity;
break;
case 2: quantity2 += quantity;
break;
case 3: quantity3 += quantity;
break;
case 4: quantity4 += quantity;
break;
case 5: quantity5 += quantity;
break;
}
cout << "Produit (1-5) / Quantité: ";
cin >> reference >> quantity;
cout << reference << quantity;
}
--------------------------------------------------------------------


1 2