Partage
  • Partager sur Facebook
  • Partager sur Twitter

[Exercices] Venez vous entraîner !

(v2)

    29 octobre 2018 à 16:12:10

    EDIT : Ah mince on ne voit plus l'exo avec la limitation de post par page, je le mets en citation du coup :

    gbdivers a écrit:

    Voici un exercice sur les catégories de valeurs (lvalue, rvalue), la surcharge de fonction avec les lvalue et rvalue references, et le perfect forwarding. En soi, cette serie d'excercices (a faire dans l'ordre) n'est pas complexe si on a compris ces notions (le code a ecrire faire une dizaine de ligne), mais cela permet justement de vérifier si vous avez compris ces notions.

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

    1. Ecrire un code qui permet de "voir" les categories de valeur

    Modifies le code suivant, de façon a afficher si la fonction f est appélée avec une lvalue ou une rvalue. Il n'est pas nécessaire d'ajouter d'autres include. Il ne faut pas non plus ajouter d'autres fonction que f. (Mais attention, comme dit dans l'introduction, il peut y avoir des surcharges de cette fonction f).

    #include <iostream>
    
    // declaration de f
    void f(...) { ... }
    
    int main() {
        // appel de f avec une lvalue
        f(...);
    
        // appel de f avec une rvalue
        f(...);
    }

    Et il faut que ce code affiche :

    f a ete appele avec une lvalue
    f a ete appele avec une rvalue

    2. La transmission

    Modifies le code de facon a ce que f soit appellé via une fonction g (sans modifier le code de f, et en remplaçant uniquement f par g dans main)

    #include <iostream>
    
    // declaration de f
    void f(...) { ... }
    
    // declaration de g
    
    void g(...) { f(...); } 
    
    int main() {
        // appel de g avec une lvalue
        g(...);
    
        // appel de g avec une rvalue
        g(...);
    }

    Quel est le problème dans ce qui est affiché ?

    3. Perfect forwarding

    Corriger le code en utilisant le perfect forwarding de façon a afficher le résultat attendu.

    Donc si j'ai bien compris, le perfect forwarding permet de garder la catégorie de valeur d'un argument, si j'en crois le fail avec le passage de la variable dans g(...) ?

    D'ailleurs, pourquoi ça s'est perdu en route ? C'est parce que la variable passée est maintenue localement dans le corps de la fonction avant d'être passée à f(...) ou quelque chose comme ça ?

    En tout cas, sympa ce petit exo' qui amène en douceur le concept.

    -
    Edité par Guit0Xx 29 octobre 2018 à 16:14:47

    • Partager sur Facebook
    • Partager sur Twitter

    ...

      29 octobre 2018 à 16:16:10

      Guit0Xx a écrit:

      Donc si j'ai bien compris, le perfect forwarding permet de garder la catégorie de valeur d'un argument, si j'en crois le fail avec le passage de la variable dans g(...) ?

      Oui.

      Guit0Xx a écrit:

      D'ailleurs, pourquoi ça s'est perdu en route ? C'est parce que la variable passée est maintenue localement dans le corps de la fonction avant d'être passée à f(...) ou quelque chose comme ça ?

      Un paramètre de fonction est une lvalue, une rvalue, ou ca-dépend ?

      • Partager sur Facebook
      • Partager sur Twitter
      Pour poser des questions ou simplement discuter informatique, vous pouvez rejoindre le discord NaN.
        29 octobre 2018 à 16:19:28

        gbdivers a écrit:

        Un paramètre de fonction est une lvalue, une rvalue, ou ca-dépend ?

        Ça sent la question piège ça, au premier abord j'aurai tendance à dire que ça dépend, mais vu le résultat obtenu précedemment, je dirai réponse A : lvalue.

        • Partager sur Facebook
        • Partager sur Twitter

        ...

          29 octobre 2018 à 16:26:12

          Oui. Le critère simple (mais ca fonctionne la plus part du temps) est d'utiliser l'operateur address-of. Est-ce que tu peux le faire sur un paramètre ? Est-ce qu'un paramètre a toujours une adresse mémoire ? A priori, oui. Donc c'est une lvalue.

          Pour les details : https://en.cppreference.com/w/cpp/language/value_category (paracétamol non fourni)

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

          (je ne peux pas poster un nouveau message pour ajouter un exo, donc je le mets a la suite de ma reponse. Mais c'est indépendant de l'exo précédent)

          Une problématique qui revient souvent (à cause de la profusion de mauvais cours C++, malheureusement) est l'utilisation de syntaxes empruntées au C dans un code C++. Il est difficile, quand on n'a pas assez de recul, de comprendre pourquoi ces syntaxes ne sont pas valides en C++. Et surtout que c'est très compliqué d'écrire un code valide en C++ en utilisant ces syntaxes.

          Le très gros problème est que les (mauvais) cours n'expliquent pas en quoi ces syntaxes sont problématiques. Quelles erreurs peuvent se produire. Et donc, même si certains cours présentent les exceptions (je ne parlerais même pas des cours qui ne parlent pas de ça), il n'est pas possible d'écrire un code correct si on ne sait pas de quoi il faut se protéger.

          Dans cette série d'exercices (à faire dans l'ordre), le but va être de partir de la problématique, d'écrire des tests pour vérifier les erreurs potentielles (approche TDD - Test Driven Development), puis de résoudre les problèmes avec des approches exception-try-catch uniquement. Et terminer sur des approches RAII.

          1. Quels sont les problèmes que l'on veut résoudre ?

          Le RAII est une solution a plusieurs problèmes. Mais lesquels ? Il faut comprendre les problèmes qui se posent pour trouver une solution pertinente.

          Un code simple d'une allocation dynamique d'un objet :

          void foo() 
          {
              ... pleins de lignes de code ici
              Object* p = new Object();
              ... pleins de lignes de code ici
              p->doSomething();
              ... pleins de lignes de code ici
              delete p;
              ... pleins de lignes de code ici
          }

          Quels sont les problèmes potentiels ? (On ne sait pas ce que fait "Object" ou "doSomething", ou ce que contient le reste du code. On regarde TOUS les problèmes qui peuvent se poser.)

          2. Les tests unitaires

          Écrire des tests unitaires qui vont reproduire ces erreurs. (On va fait au plus simple : pas besoin d'utiliser un framework de tests. On va faire 1 test = un programme)

          3. Solutions non RAII

          Et-il possible de corriger ce code, de façon a résoudre les problèmes ? Sans créer de classe RAII, uniquement avec tr-catch.

          4. Solutions RAII

          Ecrire une implémentation d'une classe RAII qui résoud ces problèmes. (Prends la semantique de unique_ptr)

          5. D'autres exemples

          Refaire l'exercice dans le cas d'un tableau dynamique.

          void foo() 
          {
              ... pleins de lignes de code ici
              Object* p = new[n] Object();
              ... pleins de lignes de code ici
              p[i]->doSomething();
              ... pleins de lignes de code ici
              delete[] p;
              ... pleins de lignes de code ici
          }

          Refaire l'exercice dans le cas d'un tableau dynamique a 2 dimensions !

          void foo() 
          {
              ... pleins de lignes de code ici
              Object** p = new[n] Object*();
              ... pleins de lignes de code ici
              p[i]->doSomething();
              ... pleins de lignes de code ici
              delete[] p;
              ... pleins de lignes de code ici
          }

          Aides !

          • Si vous bloquez sur la première question, quelques mots clés : pointeur invalide (dangling pointer), fuite mémoire (memory leak), double delete.
          • Un article très important à lire pour implémenter une classe RAII : http://www.stroustrup.com/except.pdf 

          -
          Edité par gbdivers 29 octobre 2018 à 16:40:09

          • Partager sur Facebook
          • Partager sur Twitter
          Pour poser des questions ou simplement discuter informatique, vous pouvez rejoindre le discord NaN.
            29 octobre 2018 à 21:27:16

            Bon pour le moment je n'en suis qu'à la partie non-RAII, et comme je n'avais jamais vraiment utilisé try...catch, je dois dire que ce fût sport (et encore je n'ai pas attaquer le problème avec les tableaux :lol:).

            La première chose qui me vient en tête, c'est qu'une exception peut être lancé entre la création de l'objet et le delete, ce qui provoquerait donc une fuite si rien n'est fait pour traiter.

            Pour tester, j'ai fait en sorte que la fonction doSomething() balance une exception tout en m'assurant de delete le nécessaire. Ah et j'ai ajouté un pointeur comme membre de Object, histoire d'agrémenter un peu  :

            #include <iostream>
            
            ////////////////////////////////////////////
            class Object
            {
            public:
                Object(){ a = new int(1); }
            
                ~Object(){
                    if(a != nullptr) delete a;
                    std::cout << "Object Destroyed" << '\n';
                };
            
            public:
                void doSomething(int n){
                    try{
                        if(n == 0)
                            throw(std::runtime_error{"Object::doSomething - Cannot be called with value 0"});
                    }
                    catch(...){
                        delete a;
                        a = nullptr;
                        std::cout << "(int* a) deleted" << '\n';
                        throw;
                    }
                    *a = n;
                };
            
            private:
                int* a{nullptr};
            };
            
            ////////////////////////////////////////////
            void foo()
            {
                Object* p = nullptr;
                try{
                    p = new Object();
                    p->doSomething(0);
                    delete p;
                    p = nullptr;
                }
                catch(...){
                    if(p != nullptr){
                        delete p;
                        p = nullptr;
                    }
                    throw;
                }
            }
            
            ////////////////////////////////////////////
            int main()
            {
                try{
                    foo();
                }
                catch(const std::exception& e){
                    std::cout << e.what() << '\n';
                }
            
                return 0;
            }

            Ensuite pour le souci du double deleting, j'ai pas trouvé mieux que de surcharger delete (et je suis pas sûr de la validité du bazar):

            ////////////////////////////////////////////
            void operator delete(void* p){
                if(p != nullptr){
                    p = nullptr;
                    delete(p);
                }
            }
            
            ////////////////////////////////////////////
            int main()
            {
                Object* o1 = new Object();
                Object* o2 = o1;
                delete o1;
                delete o2;
            
                return 0;
            }

            Bon du coup avant d'aller plus loin, l'ensemble est-il dégueulasse ? Et-ce qu'il y a des choses qui ne sont pas nécessaires ou d'autres qui le sont et que je n'aurai pas vu ?

            EDIT : les arrays

            #include <iostream>
            
            class Object {};
            
            ////////////////////////////////////////////
            void foo()
            {
                Object* p = nullptr;
                try{
                    p = new Object[5];
                    delete[] p;
                }
                catch(...){
                    delete[] p;
                    throw;
                }
            }
            
            ////////////////////////////////////////////
            void bar()
            {
                Object** p = nullptr;
                const unsigned rows{3};
                const unsigned cols{3};
                try{
                    p = new Object*[rows];
                    for(unsigned i = 0; i < rows; ++i){
                        p[i] = new Object[cols];
                    }
                }
                catch(...){
                    for(unsigned i = 0; i < rows; ++i){
            			p[i] = nullptr;
                        delete[] p[i];
                    }
                    delete[] p;
                    throw;
                }
            }
            
            ////////////////////////////////////////////
            int main()
            {
                try{
                    foo();
                    bar();
                }
                catch(const std::exception& e){
                    std::cout << e.what() << '\n';
                }
            
                return 0;
            }



            -
            Edité par Guit0Xx 30 octobre 2018 à 22:53:57

            • Partager sur Facebook
            • Partager sur Twitter

            ...

              30 octobre 2018 à 21:19:02 - Message modéré pour le motif suivant : Message complètement hors sujet


                25 novembre 2018 à 15:40:03

                Bonjour , jai un probleme dans un exercice et je vous que vous me aider slv, 

                Mon exercice est le suivant :

                Ecriver un programme qui trouve les N premier nombre premier avec   1 <= N <= 1000

                • Partager sur Facebook
                • Partager sur Twitter
                  25 novembre 2018 à 16:31:03

                  #include <iostream>
                  
                  static constexpr auto N = 10;
                  
                  int main() {
                      const auto primes = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41,
                                            43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97 };
                      for (auto it { std::begin(primes) }; it != std::begin(primes)+N; ++it)
                          std::cout << (*it) << " ";
                  }
                  

                  -
                  Edité par gbdivers 25 novembre 2018 à 16:31:47

                  • Partager sur Facebook
                  • Partager sur Twitter
                  Pour poser des questions ou simplement discuter informatique, vous pouvez rejoindre le discord NaN.
                    13 décembre 2018 à 12:45:56

                    Un exercice pour apprendre à debuger un code C++ old school et à le corriger. (Merci au cours C++ du site de nous fournir des codes d'exemples qui posent problèmes !)

                    La partie POO utilise un code d'exemple d'une classe Personnage, qui ressemble à ça :

                    #include <iostream>
                    #include <string>
                    
                    // ***** Weapon *****
                    class Weapon { 
                    public:
                        Weapon(std::string name, int damage);
                        int damage() const noexcept;
                    private:
                        std::string m_name;
                        int m_damage{10};
                    };
                    
                    Weapon::Weapon(std::string name, int damage) :
                        m_name{std::move(name)}, m_damage{damage}
                    {}
                    
                    int Weapon::damage() const noexcept 
                    {
                        return m_damage;
                    }
                    
                    // ***** Personnage *****
                    class Personnage {
                    public:
                        Personnage(std::string name, int damage);
                        ~Personnage() noexcept;
                    private:
                        Weapon* m_arme{nullptr};
                    };
                     
                    Personnage::Personnage(std::string name, int damage) :
                        m_arme{new Weapon{std::move(name), damage}}
                    {
                    }
                    
                    Personnage::~Personnage() noexcept
                    {
                        delete m_arme;
                        m_arme = nullptr; // inutile!
                    }
                    
                    // ***** Main *****
                    int main()
                    {
                        Personnage* david = new Personnage("épée", 100);
                        Personnage* goliath = new Personnage(*david); // on copie david
                      
                       // use david and goliath
                     
                        // david est mort, on detruit l'objet
                        delete david;
                        david = nullptr;
                     
                        // un nouvel adversaire arrive !
                        Personnage* david_survivor = new Personnage("épée", 100);
                     
                       // use david_survivor and goliath
                        
                        // clean up
                        delete goliath;
                        goliath = nullptr;
                        
                        delete david_survivor;
                        david_survivor = nullptr;
                      
                        return 0;
                    }

                    J'ai mit le code un peu à jour, en utilisant des syntaxes du C++11, mais ce n'est pas important ici. Et j'ai volontairement conservé les pointeurs nus, puisque le problème vient de là. (Comme souvent).

                    Question 1

                    Que fait ce code ?

                    Copiez-collez ce code dans compilateur en ligne (Wandbox, coliru ou IDEone) pour voir si vous aviez raison. https://wandbox.org/ 

                    Question 2

                    Remplacez les pointeurs nus dans la fonction main par des unique_ptr.

                    Que fait le code maintenant ?

                    Question 3

                    Remplacer les pointeurs nus dans la classe Personnage par des unique_ptr.

                    Que fait le code maintenant ?

                    Question 4

                    Comment corriger ce dernier code, qui utilise que des unique_ptr et plus de pointeurs nus ?

                    Question 5

                    Comment corriger le premier code, qui utilise que des pointeurs nus et pas des unique_ptr ?

                    • Partager sur Facebook
                    • Partager sur Twitter
                    Pour poser des questions ou simplement discuter informatique, vous pouvez rejoindre le discord NaN.
                      20 décembre 2018 à 12:25:05

                      Allez je me lance !

                      Question 1 :

                      Ce programme créé 2 Personnages "identiques", avec un constructeur par données (pas de souci de ce côté là) et un constructeur par copie (non spécifié, alors que la classe Personnage manipule un pointeur ..).
                      Utilisation des 2 instances créées.
                      On décide de détruire l'une des 2 instances créées avec l'opérateur delete => PROBLEME : on détruit l'arme pointée par david ET par Goliath.
                      En effet, les 2 instances de Personnage pointent vers la même arme :(
                      On décide de créer une autre instance de Personnage avec un constructeur par données (pas de problème sauf si l'allocation échoue :( ).
                      Ensuite, on décide de détruire goliath => plantage car on fait un double delete !

                      Il semblerait que coliru me donne raison lors de l'exécution.

                      *** Error in `./a.out': double free or corruption (fasttop): 0x0000000001ceac20 ***

                      Question 2 :

                      Vu que je n'ai jamais utilisé les RAII, je m'aide du site référence pour le C++ ( http://www.cplusplus.com )

                      Après une petite recherche sur le constructeur de la classe std::unique_ptr, et sur son "destructeur" (ou plutôt la méthode release) et sur la bibliothèque à insérer (ici <memory> ), j'obtiens le code suivant :

                      #include <iostream>
                      #include <string>
                      #include <memory>
                      
                      // ***** Weapon *****
                      class Weapon {
                      public:
                          Weapon(std::string name, int damage);
                          int damage() const noexcept;
                      private:
                          std::string m_name;
                          int m_damage{10};
                      };
                      
                      Weapon::Weapon(std::string name, int damage) :
                              m_name{std::move(name)}, m_damage{damage}
                      {}
                      
                      int Weapon::damage() const noexcept
                      {
                          return m_damage;
                      }
                      
                      // ***** Personnage *****
                      class Personnage {
                      public:
                          Personnage(std::string name, int damage);
                          ~Personnage() noexcept;
                      private:
                          Weapon* m_arme{nullptr};
                      };
                      
                      Personnage::Personnage(std::string name, int damage) :
                              m_arme{new Weapon{std::move(name), damage}}
                      {
                      }
                      
                      Personnage::~Personnage() noexcept
                      {
                          delete m_arme;
                          m_arme = nullptr; // inutile!
                      }
                      
                      // ***** Main *****
                      int main()
                      {
                          std::unique_ptr<Personnage> david ( new Personnage("épée", 100) );
                          std::unique_ptr<Personnage> goliath( new Personnage(*david) );  // on copie david
                      
                          // use david and goliath
                      
                          // david est mort, on detruit l'objet
                          david.release();
                      
                          // un nouvel adversaire arrive !
                          std::unique_ptr<Personnage> david_survivor ( new Personnage("épée", 100) );
                      
                      
                          // use david_survivor and goliath
                      
                          // clean up
                          goliath.release();
                      
                          david_survivor.release();
                      
                          return 0;
                      }
                      
                      Après une 1ère exécution, je n'obtiens plus d'erreurs de double libération de mémoire.
                      Ca signifie donc que le problème à la ligne 61 du code de la Q1 a été réglé.
                      J'imagine que l'appel au constructeur de la classe std::unique_ptr à la ligne 48 correspond au cas numéro 3 décrit dans la documentation http://www.cplusplus.com/reference/memory/unique_ptr/unique_ptr/
                      Quant à comprendre ce qui écrit pour le cas numéro 3, je remarque que "stored pointer" signifie "pointeur nu". Mais j'ai du mal à expliquer ce qu'il se passe véritable avec le pointeur sur Weapon.

                      Question 3 :

                      On remplace tous les pointeurs nus de la classe Personnage par un unique_ptr.
                      On obtient ainsi le code suivant :
                      #include <iostream>
                      #include <string>
                      #include <memory>
                       
                      // ***** Weapon *****
                      class Weapon {
                      public:
                          Weapon(std::string name, int damage);
                          int damage() const noexcept;
                      private:
                          std::string m_name;
                          int m_damage{10};
                      };
                       
                      Weapon::Weapon(std::string name, int damage) :
                              m_name{std::move(name)}, m_damage{damage}
                      {}
                       
                      int Weapon::damage() const noexcept
                      {
                          return m_damage;
                      }
                       
                      // ***** Personnage *****
                      class Personnage {
                      public:
                          Personnage(std::string name, int damage);
                          ~Personnage() noexcept;
                      private:
                          // Weapon* m_arme{nullptr};
                          std::unique_ptr<Weapon> m_arme {nullptr};
                      };
                       
                      Personnage::Personnage(std::string name, int damage) :
                              m_arme{new Weapon{std::move(name), damage}}
                      {
                      }
                       
                      Personnage::~Personnage() noexcept
                      {
                          m_arme.release();
                      }
                       
                      // ***** Main *****
                      int main()
                      {
                          std::unique_ptr<Personnage> david ( new Personnage("épée", 100) );
                          std::unique_ptr<Personnage> goliath( new Personnage(*david) );  // on copie david
                       
                          // use david and goliath
                       
                          // david est mort, on detruit l'objet
                          david.release();
                       
                          // un nouvel adversaire arrive !
                          std::unique_ptr<Personnage> david_survivor ( new Personnage("épée", 100) );
                       
                       
                          // use david_survivor and goliath
                       
                          // clean up
                          goliath.release();
                       
                          david_survivor.release();
                       
                          return 0;
                      }


                      Le problème, c'est que ça compile pas :/

                      main.cpp:48:46: error: call to implicitly-deleted copy constructor of 'Personnage'
                      
                          std::unique_ptr<Personnage> goliath( new Personnage(*david) );  // on copie david


                      Cette erreur est très certainement due à l'affectation d'un unique_ptr sur un autre unique_ptr dans le constructeur par copie de la classe Personnage.

                      Question 4 :

                      Etant donné qu'un type d'arme peut être utilisée par plusieurs personnages (david et goliath utilisent chacun une épée.), on a 2 solutions :
                      - Soit on arrête d'utiliser les pointeurs, et on compte sur la RAM de l'utilisateur pour contenir les nombreuses copies d'une épée.
                      - Soit on utilise l'optimisation du C++, autrement dit on utilise les shared_ptr.
                      La deuxième solution est la meilleure en terme de gains de performances.

                      Question 5 :

                      Si l'on veut rester sur les pointeurs nus, on peut utiliser la solution made in OC qui est de redéfinir le constructeur par copie de la classe Personnage, en faisant un appel au constructeur par copie de la classe Weapon pour l'attribut m_arme.
                      Puisque la classe Weapon n'utilise pas de pointeurs, il n'est pas nécessaire de redéfinir son constructeur par copie.



                      -
                      Edité par Dropper 20 décembre 2018 à 14:02:39

                      • Partager sur Facebook
                      • Partager sur Twitter
                        29 janvier 2020 à 14:13:16

                        bonjour je suis amateur et je viens de commencer la programmation ce travail pratique me semble difficile , si y a possibilité de me diriger merci

                        Écrire un programme en C permettant de saisir :

                        -un caractère représentant le code d’une figure géométrique parmi :

                        ‘c’ ou ‘C’pour un cercle

                        ‘r’ ou ‘R’pour un rectangle

                        ‘k’ ou ‘K’pour un carré

                        Dépendant de la figure, on saisit ses coordonnées (le rayon du cas de cercle ou le côté du cas de carréou …), on calcule et affiche le périmètre et la surface selon les formules du tableau suivant :

                        Figure

                        Coordonnées

                        Périmètre

                        Surface

                        Cercle

                        Rayon

                        2 x PI x rayon

                        PI x rayon x rayon

                        Rectangle

                        longueur, largeur

                        2x (longueur + largeur)

                        longueur x largeur

                        Carré

                        Côté

                        4 x côté

                        côté x côté

                        PI est une constante de type réel qui vaut 3.14159

                        Le programme permet de traiter plusieurs figures tant que l`usager décide de continuer.

                        On compte et affiche le nombre total de rectangles traités.

                        On détermine et affiche :

                        -la surface moyenne des rectangles traités.

                        -le périmètre le plus grand des cercles traités

                        -la surface la plus grande des rectangles traités.

                        -le côté le plus petit des carrés traités

                        Donnéespour la remise (mêmesdonnées => mêmes résultats => facile à corriger votre TP) :

                        -cercle de rayon 5.7

                        -carré de côté 3.9

                        -rectangle de longueur 9.2 et de largeur 6.8

                        -cercle de rayon 9.3

                        -rectangle de longueur 5.7 et de largeur 3.8

                        -cercle de rayon 3.5

                        -carré de côté 10.5



                        merci

                        • Partager sur Facebook
                        • Partager sur Twitter
                          21 avril 2020 à 13:11:22

                          • hello i would like to ask how i can  code this formula on ++c 
                          • i need just an example and i will try to code all the rest 

                          -
                          Edité par micheal1993 21 avril 2020 à 13:16:39

                          • Partager sur Facebook
                          • Partager sur Twitter
                            12 mai 2020 à 17:30:58

                            Bonjour, je propose un pendu (si ce n'est pas déjà fait par quelqu'un d'autre) avec cette solution :

                            init.cpp

                            #include <iostream>
                            #include <vector>
                            #include <cstdlib>
                            #include <ctime>
                            using namespace std;
                            int longueur_mot() {
                            	int nb = 0;
                            	do {
                            		cout << "Combien de lettres dans le mot (entre 3 et 10) ?" << endl;
                            		cin >> nb;
                            	} while (nb < 3 || nb > 10);
                            	return nb;
                            }
                            string choix_mot(int longueur) {
                                    srand(time(NULL));
                            	vector<string> mots3 = { "lui", "peu", "ail", "axe", "box", "dix", "six",
                            	"zoo", "riz", "nez", "sec" };
                            	vector<string> mots4 = { "deux", "gaze", "tank", "quoi", "moka", "taxe", "tsar" };
                            	vector<string> mots5 = { "knout", "toque", "vodka", "terre", "cycle", "whist", "larve"
                            	, "chaud", "igloo" };
                            	vector<string> mots6 = { "script", "erreur", "nickel", "chrome", "blouse", "samedi", "boulon" };
                            	vector<string> mots7 = { "attaque", "yttrium", "carbone", "babouin", "neutron", "achever", "toundra" };
                            	vector<string> mots8 = { "myocarde", "vanadium", "tablette", "jardiner", "batterie" };
                            	vector<string> mots9 = { "ytterbium", "ziggourat", "ukrainien", "agrafeuse", "oganesson" };
                            	vector<string> mots10 = { "lanthanide", "ununoctium", "lawrencium", "alexandrin", "coccinelle", "raccrocher" };
                            	string mot;
                            	switch (longueur)
                            	{
                            	case 3:
                            		mot = mots3[rand() % mots3.size()];
                            		break;
                            	case 4:
                            		mot = mots4[rand() % mots4.size()];
                            		break;
                            	case 5:
                            		mot = mots5[rand() % mots5.size()];
                            		break;
                            	case 6:
                            		mot = mots6[rand() % mots6.size()];
                            		break;
                            	case 7:
                            		mot = mots7[rand() % mots7.size()];
                            		break;
                            	case 8:
                            		mot = mots8[rand() % mots8.size()];
                            		break;
                            	case 9:
                            		mot = mots9[rand() % mots9.size()];
                            		break;
                            	case 10:
                            		mot = mots10[rand() % mots10.size()];
                            		break;
                            	default:
                            		cout << "Erreur, veuillez recommencer le jeu." << endl;
                            		mot = "";
                            		break;
                            	}
                            	return mot;
                            }



                            init.h

                            #include <iostream>
                            int longueur_mot();
                            std::string choix_mot(int longueur);

                            main.cpp

                            #include "init.h"
                            #include <iostream>
                            #include <vector>
                            #include <string>
                            using namespace std;
                            void jeu() {
                            	int nb_lettres = longueur_mot();
                            	cout << "Vous voulez un mot avec " << nb_lettres
                            		<< " lettres." << endl;
                            	string mot_final = choix_mot(nb_lettres);
                            	vector<string> utilisees = { "Vous avez essaye : " };
                            	string lettres = "azertyuiopqsdfghjklmwxcvbn";
                            	int essais(12);
                            	vector<string> mot_entre(nb_lettres, "_");
                            	string lettre_testee = utilisees[0]; 
                            	// pas dans les letters autorisees mais dans utilisees
                            	do {
                            		int nb_lettres_justes(0);
                            		for (int i = 0; i < nb_lettres; i++) {
                            			if (mot_entre[i] == string(1, mot_final[i])) {
                            				nb_lettres_justes++;
                            			}
                            		}
                            		if (nb_lettres_justes == nb_lettres) {
                            			break;
                            		}
                            		do {
                            			do {
                            				cout << "Quelle lettre ?" << endl;
                            				cin >> lettre_testee;
                            			} while (count(utilisees.begin(), utilisees.end(), lettre_testee));
                            			// si la lettre testee est dans le vecteur
                            		} while (!(lettres.find(lettre_testee) != string::npos));
                            		// si la lettre testee a deja ete utilisee
                            		utilisees.push_back(lettre_testee);
                            		if (!(mot_final.find(lettre_testee) != string::npos)) { 
                            			// si la lettre n'est pas dans le mot
                            			essais--;
                            		}
                            		else {
                            			for (int i = 0; i < nb_lettres; i++) {
                            				if (lettre_testee == string(1, mot_final[i])) {
                            					mot_entre[i] = lettre_testee;
                            				}
                            			}
                            		}
                            		for (int i = 0; i < nb_lettres; i++) {
                            			cout << mot_entre[i]; // on affiche le mot entre
                            		}
                            		cout << endl;
                            		if (essais == 1) { cout << "Vous avez le droit a encore 1 essai." << endl; }
                            		else if (essais == 0) {/*rien*/}
                            		else { cout << "Vous avez le droit a encore " << essais << " essais." << endl; }
                            		for (int i = 0; i < utilisees.size(); i++) {
                            			cout << utilisees[i], "  ";
                            		}
                            		cout << endl;
                            	} while (essais > 0);
                            	if (essais == 0) {
                            		cout << "Vous n'avez pas trouve le mot \"" << mot_final << "\"." << endl;
                            	}
                            	else {
                            		cout << "Vous avez bien trouve \"" << mot_final << "\" en " << 12 - essais << " essais." << endl;
                            	}
                            	string jouer = "du texte";
                            	do {
                            		cout << "Rejouer (oui / non) ?" << endl;
                            		cin >> jouer;
                            	} while (jouer != "oui" && jouer != "non");
                            	if (jouer == "oui") { jeu(); }
                            }
                            int main() {
                            	jeu();
                            	return 0;
                            }

                            Je préviens que je suis débutant en C++.





                            -
                            Edité par ThomasSayen 27 mai 2020 à 21:36:44

                            • Partager sur Facebook
                            • Partager sur Twitter
                              1 juin 2020 à 1:37:39

                              Voila exercice que je fais:

                              chiffre de cesar

                              Énoncé

                              Le premier algorithme que nous allons étudier, est le chiffre de César ou si on prend le cas général, le chiffrement par décalage.

                              L'algorithme consiste à décaler les lettres d'un message d'un certain nombre de position dans l'alphabet. Par exemple pour un décalage de 1, le texte:

                              SITE DU ZERO

                              devient:

                              TJUF EV AFSP

                              Le décryptage se fait de la même manière en utilisant le décalage opposé.

                              On ne considère que des messages sans accents.
                              #include <algorithm>
                              #include <iterator>
                              #include <fstream>
                              #include <iostream>
                              #include <string>
                              using namespace std;
                              class crypter
                              {
                              public:
                              char operator()(char c)
                              {
                              if(c!=' ')
                              c++;
                              return c;
                              }
                              };
                              class decrypter
                              {
                              public:
                              char operator()(char c)
                              {
                              if(c!=' ')
                              c--;
                              return c;
                              }
                              };
                              int main()
                              {
                              ifstream fichier("texte");
                              ofstream flux("texte",ios::app);//app pour ajouter un texte
                              istream_iterator<char> it(fichier);
                              istream_iterator<char> fin;
                              ostream_iterator<char> it2(flux);
                              
                              string ch;
                              while(it!=fin)
                              {
                              ch+=*it;
                              it++;
                              }
                              int choix;
                              
                              while(1)
                              {
                              do
                              {cout<<"\n0:ajoute ligne\n1:cryptage du fichier texte\n2:quitter\n";
                              cin>>choix;
                              }while(!(choix >=0)&&(choix<3));
                              if(choix==0)
                              {
                              cout<<"texte:\n";
                              cin>>ch;
                              transform(ch.begin(),ch.end(),ch.begin(),crypter());
                              copy(it,fin,it2);
                              cout<<"le msg dans fichier texte cryptee : \n"<<ch<<endl;
                              flux<<ch;
                              }
                              else if(choix==1)
                              {transform(ch.begin(),ch.end(),ch.begin(),decrypter());
                              cout<<"le msg  decryptee : \n"<<ch;
                              }
                              else
                              exit (EXIT_SUCCESS);
                              }
                              }
                              
                              le programme affiche la suite:
                              Mais le fichier texte reste vide et le console n'accepte pas des lignes avec des espaces.
                              Comment faire pour corriger les erreurs?
                              • Partager sur Facebook
                              • Partager sur Twitter
                                1 juin 2020 à 10:49:52

                                Quelques remarques sur ton code pour commencer:

                                penses à indenter correctement ton code, cela permettra de le relire beaucoup plus facilement, surtout pour ceux qui ne regardaient pas au dessus de ton épaule au moment où tu l'écrivais, et qui n'ont que ton code pour essayer de comprendre ton raisonnement ;)

                                Ensuite, l'utilisation de la directive using namespace std; est une très mauvaise pratique...  ==>Voici pourquoi<==.

                                Ensuite, je constate que tu essaye d'ouvrir en même temps ton fichier (nommé texte) en mode lecture (std::ifstream) et en mode écriture (std::ofstream) -- ce qui est déjà une très mauvaise idée (j'en parlerai un peu plus bas) -- et que tu  ne vérifie absolument pas si ces deux ouvertures réussissent, un peu comme si nous vivions dans le monde des bisounours et que ces deux actions n'avaient pas d'autre choix que de réussir, ce qui est une encoreplus mauvaise idée.

                                Je vois, en effet, deux situations dans lesquelles l'une de ces ouvertures de fichier au moins pourra échouer:

                                La toute première fois que tu exécuteras ton programme, tout de suite après l'avoir compilé, le fichier (nommé texte) n'existe sans doute pas (encore).

                                Son ouverture en lecture seule (qui est provoquée par la création de ta variable fichier, qui est de type std::ifstream) ne peut donc pas réussir, vu qu'il est impossible d'ouvrir (sans le créer) une fichier qui ... n'existe pas.

                                Lors de toutes les exécutions suivantes de ton programme, nous nous heurtons à la première raison que j'ai invoquée plus haut à savoir que le système d'exploitation va systématiquement mettre un "verrou" sur tous les fichiers qui sont ouverts.

                                Ce verrou va systématiquement empêcher le fichier d'être ouvert une fois de plus "ailleurs" (potentiellement dans la même application), de manière à s'assurer qu'il n'y ait aucune modification entre le moment où l'application lit la première ligne du fichier et le moment où elle lira la deuxième ligne (ou pire, entre le moment où l'application essayera de lire le troisième caractère de la première ligne et le moment où elle essayera de lire le quatrième)

                                Ta variable variable flux (qui est de type std::ofstream) correspond donc à un fichier qui n'a pas été ouvert, à cause du verrou posé sur le fichier lors de la création de la variable fichier.

                                Quoi qu'il advienne, tu te trouveras donc face à un problème de fichier non ouvert lorsque tu déclares tes itérateurs aux lignes suivantes:

                                lors de la première exécution de ton programme, comme fichier n'a pas pu être ouvert, it (pour lequel j'aurais sans doute choisi un autre nom) est donc forcément déjà égal à fin.  Ta boucle

                                    string ch;
                                    while(it!=fin)
                                    {
                                        ch+=*it;
                                        it++;
                                    }

                                (correctement indentée pour l'occasion) n'a donc aucune chance de s'exécuter (lors de la toute première exécution du programme), vu que la condition pour entrer dans la boucle (it doit être différent de fin) n'est pas respectée.

                                (notes que ce n'est pas un problème en soi, car, même si le fichier existait à ce moment précis, il serait -- a priori -- vide, ce qui reviendrait au même)

                                D'un autre coté, lors de toutes les exécutions suivantes de ton programme, tu utilises l'instruction

                                            copy(it,fin,it2);

                                pour ajouter le texte chiffré dans le fichier.

                                Or, a priori, it2 est un itérateur sur un flux invalide, vu qu'il n'a pas pu être ouvert.  Mais, bien pire encore...  Pourrais tu me rappeler ce que vaut it à ce moment précis de l'exécution, sachant que, si le fichier existe, tu sera forcément passé dans cette fameuse boucle

                                    string ch;
                                    while(it!=fin)
                                    {
                                        ch+=*it;
                                        it++;
                                    }

                                Que penses tu donc qui sera écrit dans it2 (que j'aurais aussi nommé autrement) grâce à cette fameuse instruction std::copy, même si it2 était un itérateur de flux valide ????


                                -
                                Edité par koala01 1 juin 2020 à 10:50:35

                                • Partager sur Facebook
                                • Partager sur Twitter
                                Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
                                  2 juin 2020 à 9:58:01

                                  j'essaye de corriger code de façon d'ouvrir fichier en mode d’écriture et lecture .maintenant,le fichier a écrit correctement

                                  #include <algorithm>
                                  #include <iterator>
                                  #include <fstream>
                                  #include <iostream>
                                  #include <string>
                                  using namespace std;
                                  class crypter
                                  {
                                  public:
                                  char operator()(char c)
                                  {
                                  if(c!=' ')
                                  c++;
                                  return c;
                                  }
                                  };
                                  class decrypter
                                  {
                                  public:
                                  char operator()(char c)
                                  {
                                  if(c!=' ')
                                  c--;
                                  return c;
                                  }
                                  };
                                  int main()
                                  {
                                  fstream fichier("texte",ios::in|ios::out|ios::trunc);
                                  string ch;
                                  
                                  if(!fichier)
                                  {
                                  cout<<"Erreur d'ouverture le fichier"<<endl;
                                  exit(EXIT_FAILURE);
                                  }
                                  
                                  int choix;
                                  
                                  while(1)
                                  {
                                  do
                                  {cout<<"\n0:ajoute ligne\n1:decryptage du fichier texte\n2:quitter\n";
                                  cin>>choix;
                                  }while(!(choix >=0)&&(choix<3));
                                  if(choix==0)
                                  {
                                  cout<<"texte:\n";
                                  cin>>ch;
                                  transform(ch.begin(),ch.end(),ch.begin(),crypter());
                                  fichier<<ch<<endl;
                                  cout<<"le msg dans fichier texte cryptee : \n"<<ch<<endl;
                                  }
                                  else if(choix==1)
                                  {
                                  while(getline(fichier,ch))//pour mettre chaque ligne de fichier dans ch
                                  {
                                  transform(ch.begin(),ch.end(),ch.begin(),decrypter());
                                  cout<<ch;
                                  }
                                  }
                                  else
                                  exit (EXIT_SUCCESS);
                                  }
                                  fichier.close();
                                  return 0;
                                  }
                                  

                                  mais ,il y a des problèmes sur les lignes suivantes pour lire le fichier:

                                  else if(choix==1)
                                  {
                                  while(getline(fichier,ch))//pour mettre chaque ligne de fichier dans ch
                                  {
                                  transform(ch.begin(),ch.end(),ch.begin(),decrypter());
                                  cout<<ch;
                                  }
                                  }




                                  -
                                  Edité par HammaGuibane1 2 juin 2020 à 10:01:17

                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    2 juin 2020 à 13:54:20

                                    Il va falloir réessayer, car, il y a deux règles à respecter:

                                    • les données (variables) doivent être déclarées au plus près de leur première utilisation
                                    • on n'ouvre un fichier qu'une fois qu'on sait comment il sera utilisé

                                    Cela devrait t'amener à respecter d'avantage le SRP (le principe de la responsabilité unique), car, pour l'instant, si on y réfléchit un tout petit peu, ta fonction main prend les responsabilités

                                    1. d'afficher un menu (ligne 43)
                                    2. de récupérer le choix de l'utilisateur et de l'analyser (lignes 44 et 45)
                                    3. de demander à  l'utilisateur d'introduire un texte (ligne 48)
                                    4. de récupérer le texte introduit par l'utilisateur (ligne 49)
                                    5. de chiffrer le texte obtenu (ligne 50)
                                    6. de déchiffrer le texte qui se trouve dans un fichier (lignes 66 à 60)
                                    7. et la plus importante de toutes: de servir de point d'entrée au programme

                                    Cela fait sept responsabilités différentes.  C'est six de trop, en vertu du SRP.  Crois tu pouvoir corriger cela?

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                    Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
                                      2 juin 2020 à 16:09:42

                                      Bonjour à tous, pourriez-vous me conseiller sur le code que j'ai posté s'il vous plaît ?

                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        2 juin 2020 à 21:37:16

                                        koala01 a écrit:

                                        Il va falloir réessayer, car, il y a deux règles à respecter:

                                        • les données (variables) doivent être déclarées au plus près de leur première utilisation
                                        • on n'ouvre un fichier qu'une fois qu'on sait comment il sera utilisé

                                        Cela devrait t'amener à respecter d'avantage le SRP (le principe de la responsabilité unique), car, pour l'instant, si on y réfléchit un tout petit peu, ta fonction main prend les responsabilités

                                        1. d'afficher un menu (ligne 43)
                                        2. de récupérer le choix de l'utilisateur et de l'analyser (lignes 44 et 45)
                                        3. de demander à  l'utilisateur d'introduire un texte (ligne 48)
                                        4. de récupérer le texte introduit par l'utilisateur (ligne 49)
                                        5. de chiffrer le texte obtenu (ligne 50)
                                        6. de déchiffrer le texte qui se trouve dans un fichier (lignes 66 à 60)
                                        7. et la plus importante de toutes: de servir de point d'entrée au programme

                                        pourriez-vous comment je fais pour corriger cela ?  pourriez- vous m'expliquer pourquoi six est trop svp?

                                        -
                                        Edité par HammaGuibane1 2 juin 2020 à 21:39:38

                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          2 juin 2020 à 22:47:32

                                          Ben, comme le dit si bien le nom du principe que j'invoque, c'est le principe de la responsabilité unique. C'est à dire que chaque fonction, chaque donnée, chaque type de donnée ne devrait faire qu'une seule chose, ne devrait permettre d'atteindre qu'un seul objectif.

                                          Et du coup, ben, une fonction qui fait sept chose différentes, qui poursuit sept objectifs différents, elle s'occupe de six choses de trop ;)

                                          De même, en vertu de ce principe, ton fichier qui sert à la lecture et à l'écriture, il poursuit deux objectifs, et il sert donc à une chose de trop.

                                          Le mot clé pour résoudre ce problème est : fonctions.  Tu dois créer une fonction pour chaque objectif bien particulier, et, de cette manière, tu pourras les "combiner à ta guise" en fonction des besoins que tu essayes de remplir

                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                          Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
                                            3 juin 2020 à 12:03:36

                                            #include <algorithm>
                                            #include <iterator>
                                            #include <fstream>
                                            #include <iostream>
                                            #include <string>
                                            using namespace std;
                                            string ch;
                                            class crypter
                                            {
                                            public:
                                            char operator()(char c)
                                            {
                                            if(c!=' ')
                                            c++;
                                            return c;
                                            }
                                            };
                                            class decrypter
                                            {
                                            public:
                                            char operator()(char c)
                                            {
                                            if(c!=' ')
                                            c--;
                                            return c;
                                            }
                                            };
                                            void lire_fichier(const string& nom)
                                            {
                                            fstream fichier(nom,ios::in);
                                            while(getline(fichier,ch))//pour mettre chaque ligne de fichier dans ch
                                            {
                                            transform(ch.begin(),ch.end(),ch.begin(),decrypter());
                                            cout<<ch;
                                            }
                                            }
                                            void ecrire_fichier(const string& nom)
                                            {
                                            
                                            fstream fichier(nom,ios::out|ios::in);
                                            cout<<"texte:\n";
                                            cin>>ch;
                                            transform(ch.begin(),ch.end(),ch.begin(),crypter());
                                            fichier<<ch<<endl;
                                            cout<<"le msg dans fichier texte cryptee : \n"<<ch<<endl;
                                            }
                                            void menu(const string nom)
                                            {
                                            int choix;
                                            while(1)
                                            {
                                            do
                                            {cout<<"\n0:ajoute ligne\n1:cryptage du fichier texte\n2:quitter\n";
                                            cin>>choix;
                                            }while(!(choix >=0)&&(choix<3));
                                            if(choix==0)
                                            {
                                            ecrire_fichier(nom);
                                            }
                                            else if(choix==1)
                                            lire_fichier(nom);
                                            else
                                            exit (EXIT_SUCCESS);
                                            }
                                            }
                                            int main()
                                            {
                                            fstream fichier("texte",ios::in|ios::out);
                                            if(!fichier)
                                            {
                                            cout<<"Erreur d'ouverture le fichier"<<endl;
                                            exit(EXIT_FAILURE);
                                            }
                                            menu("texte");
                                            fichier.close();
                                            return 0;
                                            }
                                            

                                            c'est ça sava? mais il y a une probleme :le programme n'accepte que des chaines sans espaces.Si on lit une chaine avec des espaces,il sera une boucle infinie(systeme planté c-a-d ,le systeme ios demande de fermer le console ) et merci bcp a vous

                                            -
                                            Edité par HammaGuibane1 3 juin 2020 à 12:05:24

                                            • Partager sur Facebook
                                            • Partager sur Twitter

                                            [Exercices] Venez vous entraîner !

                                            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                            • Editeur
                                            • Markdown