IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

sstream et saisie cin


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé

    Homme Profil pro
    développeur à la maison
    Inscrit en
    Septembre 2006
    Messages
    441
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Tarn et Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : développeur à la maison

    Informations forums :
    Inscription : Septembre 2006
    Messages : 441
    Billets dans le blog
    16
    Par défaut sstream et saisie cin
    Bonjour,

    pourquoi b est toujours à 0 ?

    une idée ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    #include <iostream>
    #include <string>
    #include <sstream>
     
    int main(){
      std::cout<<"a= ";
      int a;
      std::string saisie;
      std::stringstream geek;
      std::cin>>saisie;
      geek<<saisie;
      geek>>a;
      geek.flush();
      std::cout<<"b= ";
      int b;
      std::cin>>saisie;
      geek<<saisie;
      geek>>b;
      std::cout<<a<<' '<<b<<std::endl;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    $ ./a.out 
    a= 56
    b= 12
    56 0

  2. #2
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 559
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 559
    Par défaut
    Coincé par les CR-LF ?

  3. #3
    Expert confirmé
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 306
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 306
    Par défaut
    Hum...

    Je n'utilise jamais les stringstream en I/O. J'utilise uniquement l'un ou l'autre.

    Quant au reset, je fais ça avec `iss.str("")`, voire directement dans ton cas avec `iss.str(saisie)`.

    Au passage, toujours tester les extractions. Ca permettrait de savoir quand cela commence à ne plus aller.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  4. #4
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 752
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 752
    Par défaut
    Hello,

    Le problème vient du fait que geek.flush() ne sert pas à réinitialiser le flux pour une réutilisation.

    Chronologie dans votre programme :

    • geek << saisie("56") : Le flux contient "56".
    • geek >> a : Le flux lit "56". Il arrive à la fin de la chaîne interne. Le drapeau eofbit (End Of File) est levé.
    • geek.flush() : Cette commande synchronise les tampons de sortie, mais elle n'efface pas les drapeaux d'erreur (EOF) et ne vide pas le contenu lu.
    • geek << saisie("12") : Vous ajoutez "12" au flux. Le flux contient maintenant techniquement "12" (ou une suite selon la position), mais il est toujours considéré comme "en erreur/fini" à cause du eofbit.
    • geek >> b : Comme le drapeau EOF (ou failbit) est actif, l'opération de lecture refuse de s'exécuter. b n'est pas modifié et reste à 0.


    Pour réutiliser un stringstream, vous devez faire deux choses :

    • geek.clear() : Pour remettre les drapeaux d'état (comme EOF) à zéro.
    • geek.str("") : Pour vider le texte précédent du tampon (sinon vous allez ajouter "12" à la suite de l'ancien contenu s'il n'a pas été entièrement consommé).


    Une proposition de code corrigé,

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    #include <iostream>
    #include <string>
    #include <sstream>
     
    int main(){
        std::cout << "a= ";
        int a;
        std::string saisie;
        std::stringstream geek;
     
        // Première lecture
        std::cin >> saisie;
        geek << saisie;
        geek >> a;
     
        // --- CORRECTION ICI ---
        geek.clear();  // 1. Réinitialise les drapeaux d'erreur/EOF
        geek.str("");  // 2. Vide le contenu du buffer
        // ----------------------
     
        std::cout << "b= ";
        int b;
        std::cin >> saisie;
        geek << saisie; // Maintenant le flux est propre et prêt
        geek >> b;
     
        std::cout << a << ' ' << b << std::endl;
     
        return 0;
    }
    Si vous n'êtes pas contraint d'utiliser stringstream pour un exercice,
    l'approche moderne en C++ (depuis C++11) pour convertir une string en intest d'utiliser std::stoi.

    C'est plus simple et évite ces problèmes d'état :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    // Remplacer toute la mécanique stringstream par :
    std::cin >> saisie;
    a = std::stoi(saisie);
    Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
    La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

  5. #5
    Membre éclairé

    Homme Profil pro
    développeur à la maison
    Inscrit en
    Septembre 2006
    Messages
    441
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Tarn et Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : développeur à la maison

    Informations forums :
    Inscription : Septembre 2006
    Messages : 441
    Billets dans le blog
    16
    Par défaut
    merci à vous tous
    voici le source final:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    #include <iostream>
    #include <string>
     
    int main(){
      std::cout<<"Salaire : ";
      std::string saisie;
      std::cin>>saisie;
      int salaire=std::stoi(saisie);
      std::cout<<"Impôts : ";
      std::cin>>saisie;
      int impots=std::stoi(saisie);
      std::cout<<"Remboursement de l'hypothèque : ";
      std::cin>>saisie;
      int remb_hypotheque=std::stoi(saisie);
      std::cout<<"Remboursement du prêt étudian : ";
      std::cin>>saisie;
      int remb_etudiant=std::stoi(saisie);
      std::cout<<"Remboursement du prêt véhicule : ";
      std::cin>>saisie;  
      int remb_vehicule=std::stoi(saisie);
      std::cout<<"Remboursement des dettes de la carte de crédit : ";
      std::cin>>saisie;
      int remb_carte=std::stoi(saisie);
      std::cout<<"Autre dépenses : ";
      std::cin>>saisie;
      int autres_depenses=std::stoi(saisie);
      std::cout<<"remboursement prêt bancaire : ";
      std::cin>>saisie;  
      int remb_banque=std::stoi(saisie);
      std::cout<<"Dépenses enfants : ";
      std::cin>>saisie;
      int depenses_enfants=std::stoi(saisie);
      std::cout<<"Cashflow : ";
      std::cin>>saisie;
      int cashflow=std::stoi(saisie);
      std::cout<<"Caisse : ";
      std::cin>>saisie;
      int caisse=std::stoi(saisie);
      std::cout<<"Votre salaire est de "<<salaire<<std::endl;
      std::cout<<"Votre cashflow est de "<<cashflow<<std::endl;
      std::cout<<"Votre caisse est de "<<caisse<<std::endl;
      std::cout<<"Vos impôts sont de "<<impots<<std::endl;
      std::cout<<"Vos remboursements d'hypothèque sont de "<<remb_hypotheque<<std::endl;
      std::cout<<"Vos remboursements du pret étudiant sont de "<<remb_etudiant<<std::endl;
      std::cout<<"Vos remboursements du pret du véhicule sont de "<<remb_vehicule<<std::endl;
      std::cout<<"Vos remboursements des dettes de carte de crédit sont de "<<remb_carte<<std::endl;
      std::cout<<"Vos autres dépenses sont de "<<autres_depenses<<std::endl;
      std::cout<<"Vos remboursements du pret bancaire sont de "<<remb_banque<<std::endl;
      std::cout<<"Vos dépenses pour les enfants sont de "<<depenses_enfants<<std::endl;
      exit(0);
    }
    @fred1599 : je viens de faire l'expérience de la différence de la qualité des réponses humaine par repport à l'IA. L'IA m'a juste conseillé geek.clear();geek.str("")

  6. #6
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 752
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 752
    Par défaut
    exit(0); nécessite la cstdlib

    Sur certaines plateformes, il est possible que <iostream> ou <string> inclue en interne <cstdlib>.
    Si c'est le cas, le symbole std::exit (ou ::exit par pollution de l'espace de noms global) sera disponible, et le code compilera par accident.

    Un compilateur strict, respectant le principe que l'utilisateur doit déclarer ce qu'il utilise, rejettera le code avec une erreur :
    "use of undeclared identifier 'exit'".
    → C'est le comportement attendu d'un code C++ correct et portable.

    Remarque : La suppression de exit() est une solution architecturale supérieure.




    Exemple de saisie utilisateur

    Le code demande :
    std::cout << "Salaire : ";

    - Si l'utilisateur entre 2500 (suivi de Entrée), tout se passe bien.
    - Mais si l'utilisateur entre 2500 Euros, voici la séquence désastreuse :

    1. std::cin >> saisie lit jusqu'au premier espace → extrait "2500".
    2. Le flux contient encore " Euros\n".
    3. std::stoi("2500") réussit.
    4. Le programme affiche "Impôts : ".
    5. Le second std::cin >> saisie consomme immédiatement "Euros".
    6. Le programme tente std::stoi("Euros") → exception.




    Exceptions de std::stoi

    Introduite en C++11, std::stoi lance des exceptions :

    - std::invalid_argument : si aucune conversion possible ("Euros", "Hello", chaîne vide).
    - std::out_of_range : si la valeur dépasse les limites de int (ex: 9999999999).

    Problème : Sans try-catch, l'exception atteint main → std::terminate() → arrêt brutal.




    Durée de vie et nettoyage

    - En C++, les variables locales sont détruites à la fin de la fonction (Stack Unwinding).
    - std::exit() termine immédiatement, sans détruire les variables locales.
    - return 0; dans main garantit un nettoyage complet et sûr.
    → exit() doit être réservé aux erreurs irrécupérables.




    EXIT_SUCCESS et EXIT_FAILURE

    Le standard définit :
    - EXIT_SUCCESS (généralement 0)
    - EXIT_FAILURE

    Utiliser return 0; est plus riche sémantiquement que exit(0);.




    Problème de conception : Cashflow

    Le programme demande :
    - Revenus (Salaire)
    - Dépenses (Impôts, prêts, etc.)
    - Cashflow

    Erreur conceptuelle : Le Cashflow est une donnée dérivée :
    Cashflow = Revenus - Σ Dépenses

    Risques :
    - Erreur de calcul (l'utilisateur doit calculer lui-même).
    - Incohérence (ex: Revenus=3000, Dépenses=2000, Cashflow=5000).

    → Un logiciel correct doit garantir l'intégrité des données.




    Type utilisé : int

    - int ne gère pas les décimales → pas de centimes.
    - double ou float : erreurs d'arrondi binaires.
    - Approche professionnelle : entiers représentant les centimes ou classes Decimal.

    Conclusion : Conserver int est acceptable pour la simplicité, mais limité en précision.
    Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
    La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. flux de saisie : fichier ou cin au choix
    Par ternel dans le forum C++
    Réponses: 3
    Dernier message: 24/06/2014, 19h27
  2. Bloquer saisie cin>> à 1 caractère: possible?
    Par Christophe59 dans le forum C++
    Réponses: 1
    Dernier message: 22/03/2009, 22h24
  3. Problème parasitage tampon saisie cin
    Par pjtuloup dans le forum C++
    Réponses: 7
    Dernier message: 25/05/2008, 09h25
  4. Réponses: 2
    Dernier message: 10/03/2008, 13h08
  5. [cin] saisie avec test
    Par crakocrako dans le forum C++
    Réponses: 1
    Dernier message: 27/02/2008, 11h23

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo