Partage
  • Partager sur Facebook
  • Partager sur Twitter

Cryptage C++

Boucle While et tableaux

    5 octobre 2018 à 10:54:13

    Bonjour, je code actuellement en C++ et j'ai un exercice de cryptage. Le sujet est le suivant :

    "On dispose de données sous forme d'entiers compris entre 0 et 9999. On choisit de coder ces données avant
    transmission sur ligne téléphonique, pour les garder secrètes. Le programme doit lire un entier à 4 chires et le
    crypter comme suit :
    chaque chire est remplacé par (chire + 7) modulo 10, puis,
    le premier et le troisième chire sont permutés, puis
    le second et le quatrième chire sont permutés.
    le programme doit ensuite acher le nombre crypté.
    On commencera par extraire du nombre et acher les 4 chires correspondants aux milliers, centaines, dizaines et
    unités.
    Crypter en utilisant une boucle est un tableau pour la dissociation du nombre.".

    J'ai donc essayé de diverses manières mais de un j'ai un problème via mon tableau et je n'ai toujours pas utilisé de boucle While car je ne saisis pas l'utilité dans ce programme.

    Voici mon code:

    #include <iostream>
    using namespace std;
    
    int main()
    {
        int m,c,d,u,i;
        cin>>i;
        m = i/1000;
        c = (i/100);
        d = (i%100)/10;
        u = i%10;
        m = (m+7)%10;
        c = (c+7)%10;
        d = (d+7)%10;
        u = (u+7)%10;    
        int tab[]={m,c,d,u};
        for(int f;f<5;f++){
            cout<<tab[f];
        }
        return 0;
    }

    Merci d'avance pour votre aide.

    -
    Edité par hugomocq 5 octobre 2018 à 10:55:59

    • Partager sur Facebook
    • Partager sur Twitter
      5 octobre 2018 à 11:31:29

      Lu',

      casser un nombre en chiffres est un algorithme assez "bete" qui se fait en 2 lignes (avec une boucle biensur). Dans ce genre de cas on prend un exemple (genre 5432) et on essaye de "réflechir" un peu.

      Dans ton cas: 

      hugomocq a écrit:

      #include <iostream>
      using namespace std;
      
      int main()
      {
          int m,c,d,u,i;
          cin>>i;
          m = i/1000;
          c = (i/100);
          d = (i%100)/10;
          u = i%10;
          m = (m+7)%10;
          c = (c+7)%10;
          d = (d+7)%10;
          u = (u+7)%10;    
          int tab[]={m,c,d,u};
          for(int f;f<5;f++){
              cout<<tab[f];
          }
          return 0;
      }

      si on prends le nombre 5432, on obtient pour les valeurs m,c,d,u : 5, 54 , 3.2, 2.... En bref, ce n'est même pas la peine de continuer le reste de l'exo si ta "découpe" est fausse.



      -
      Edité par eugchriss 5 octobre 2018 à 11:31:57

      • Partager sur Facebook
      • Partager sur Twitter

      Eug

        5 octobre 2018 à 11:35:49

        Lu'!

        D'abord un rappel : "crypter", ça n'existe pas : https://chiffrer.info/ .

        Ensuite, pour ton exercice, on te dit d'utiliser un tableau c'est à dire de commencer par transformer ton nombre en tableau. Le début de ton programme doit être :

        int nombre[4] ;
        int i ;
        std::cin >> i ;
        
        //on met le nombre i transformé dans nombre

        Et pour ça, on va utiliser un boucle.

        Autres notes :

        • n'utilise pas "using namespace std" (raison + que faire),
        • plutôt que "int nombre[4]" on préférerait "std::array<int, 4>".
        • Partager sur Facebook
        • Partager sur Twitter

        Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C

          5 octobre 2018 à 12:26:07

          Salut,

          La première chose qu'il faut savoir, c'est que pour chaque verbe (ou groupe verbal) que tu rencontre dans ton analyse des besoins, tu devrais trouver une fonction dans ton code et que pour chaque nom (ou groupe nominal) que tu rencontre dans ton analyse des besoins, tu devrais trouver une donnée ou un type de donnée équivalent dans le code.

          Cela t'aidera à respecter l'un des principes de base primordiaux qu'est le SRP (pour Single Responsability Principle)

          D'après ton analyse, nous aurons donc besoin d'au moins quatre fonctions:

          • une première pour diviser le nombre à transmettre
          • une deuxième pour crypter le résultat de la première
          • une troisième pour décrypter le résultat de l'encryption
          • une quatrième pour recréer le nombre sur base des différents chiffres obtenus (après encryptions ou décryptage)

          Comme je n'ai pas envie de m'amuser à introduire tout plein de valeurs à la main, je vais rajouter une cinquième fonction qui se chargera de choisir un nombre de manière aléatoire qui sera compris entre 1 et 9999.

          Et, parce que j'ai envie de voir les résultats intermédiaires, je vais créer une fonction qui m'affichera -- en plus -- le résultat de la "subdivision" du nombre en chiffres.

          Nous voulons donc pouvoir représenter les quatre chiffres qui composent les valeurs comprises entre 0001 et 9999. Plutôt que de créer une variable séparée pour chacune d'elle, nous aurions largement intérêt à les regrouper dans une collection spécifique, et à décider "arbitrairement" que le premier représentera les millier, le deuxième représentera les centaines, le troisième représentera les dizaines et le dernier représentera les unités.

          Par facilité, nous serions bien inspirés de créer une énumération pour représenter cette décision.  Elle prendrait sans doute une forme proche de

          enum position{
          	thosands, // == 0
          	hundreds, // == 1
          	tens,     // == 2
          	units,    // == 3
          	MAX       // parce que les tableaux sont indexés
                            // à partir de 0, correspond au nombre
                            // d'éléments du tableau
          };

          Et nous pourrions l'utiliser pour définir le type de donnée particulier dont on a besoin pour représenter notre "collection de chiffres" sous une forme proche de

          // !!! nécessite l'inclusion du fichier 
          using SubValues = std::array<int, MAX>;

          Ensuite, nous devons prévoir les fonctions qui s'occuperont de tout pour nous. La première dont nous avons besoin est celle qui s'occupera de subdiviser le nombre d'origine, et qui pourrait ressembler à quelque chose comme

          SubValues divide(int origin){
              SubValues subValues;
              size_t pos=units;
              while(origin>0){
                  // je vais te laisser réfléchir à comment faire,
                  // ce serait trop facile autrement    
              }
              return subValues;
          }

          La deuxième fonction dont nous aurons besoin, ce sera celle qui nous permettra d'afficher les différents chiffres obtenus.  Elle pourrait ressembler à quelque chose comme

          void printCiffers(SubValues const & values){
              //!!! nécessite l'inclusion du fichier 
              static const std::array<std::string, MAX> str{"milliers","centaines,", "dizaines", "unités"};
              size_t pos{thosands};
              while(pos< MAX){
                  std::cout<<str[pos]<<" : "<<values[pos]<<"\n";
                  ++pos;
              }
          }

          Mais ce n'est bien sur qu'un exemple, elle pourrait être très largement modifiée ;)

          La troisième fonction dont nous avons besoin, ce sera celle qui pourra crypter les données.  Elle pourrait prendre une forme proche de

          void encrypt(SubValues & value){
              for(auto & it : value){
                  // calculer la nouvelle valeur de it ... cela les 
                  // modifiera automatiquement dans notre collection
                  // d'origine
              }
              // intervertir miliiers et dizaines
              // intervertir centaines et unités
          }

           Comme je veux pouvoir voir le nombre qui résulte de l'encryption, je vais tout de suite créer la fonction qui me recrée un nombre sur base des quatre valeurs dont je dispose.  Elle pourrait prendre une forme proche de

          int merge(SubValues const & value){
          	int result{0};
          	for(size_t pos{thosands}; pos<MAX;++pos){
          		result+= value[pos];
          		if(pos!=units)
          			result *=10;
          	}
          	return result;
          }

          Selon la forme que pourrait prendre la transmission, elle pourrait d'ailleurs très bien servir à cet effet aussi ;)

          Mais, comme nous ne savons rien de la méthode de transmission, nous ferons "comme si" elle était inutile dans ce cas là...

          La fonction suivante dont nous avons besoin est celle qui nous permettra de décrypter les données. Elle pourrait prendre la forme de

          void decrypt(SubValues & value){
              // intervertir milliers et dizaines
              // intervertir centaiens et unités
              for(auto & it : value){
                  // rétablir la valeur d'origine pour it ...
                  // cela modifiera notre collection d'origine
              }
          }

          Et il ne nous manque plus que la fonction qui générera les nombres aléatoires.  Elle pourrait prendre la forme de

          int randomValue(){
              // !!! nécessite l'inclusion du fichier <random>
              static std::random_device rd;  
              static std::mt19937 gen(rd()); 
              static std::uniform_int_distribution<> dis(1, 9999);
              return dis(gen);
          }

          Une fois toutes ces fonctions créées, nous devrons, bien sur, mettre tout cela "en musique" dans la fonction principale.  Elle pourrait prendre une forme proche de

          int main(){
          	int value= randomValue();
          	std::cout<<"original value :"<<value<<"\n";
          	auto sub = divide(value);
          	printCiffers(sub);
          	encrypt(sub);
          	std::cout<<"After encryption :\n";
          	printCiffers(sub);
          	std::cout<<"Or : "<<merge(sub)<<"\n";
          	decrypt(sub);
          	std::cout<<"final result = "<<merge(sub)<<"\n";
          	return 0;
          }
          

          qui est -- ici -- écrite de manière à nous montrer toutes les étapes par lesquelles nous passons lors du cryptage et du décryptage des données ;)

          • 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
            5 octobre 2018 à 20:18:16

            Je réitère le site http://chiffrer.info.

            • Partager sur Facebook
            • Partager sur Twitter

            git is great because Linus did it, mercurial is better because he didn't.

              9 octobre 2018 à 9:22:40

              koala01 a écrit:

              Salut,

              La première chose qu'il faut savoir, c'est que pour chaque verbe (ou groupe verbal) que tu rencontre dans ton analyse des besoins, tu devrais trouver une fonction dans ton code et que pour chaque nom (ou groupe nominal) que tu rencontre dans ton analyse des besoins, tu devrais trouver une donnée ou un type de donnée équivalent dans le code.

              Cela t'aidera à respecter l'un des principes de base primordiaux qu'est le SRP (pour Single Responsability Principle)

              D'après ton analyse, nous aurons donc besoin d'au moins quatre fonctions:

              • une première pour diviser le nombre à transmettre
              • une deuxième pour crypter le résultat de la première
              • une troisième pour décrypter le résultat de l'encryption
              • une quatrième pour recréer le nombre sur base des différents chiffres obtenus (après encryptions ou décryptage)

              Comme je n'ai pas envie de m'amuser à introduire tout plein de valeurs à la main, je vais rajouter une cinquième fonction qui se chargera de choisir un nombre de manière aléatoire qui sera compris entre 1 et 9999.

              Et, parce que j'ai envie de voir les résultats intermédiaires, je vais créer une fonction qui m'affichera -- en plus -- le résultat de la "subdivision" du nombre en chiffres.

              Nous voulons donc pouvoir représenter les quatre chiffres qui composent les valeurs comprises entre 0001 et 9999. Plutôt que de créer une variable séparée pour chacune d'elle, nous aurions largement intérêt à les regrouper dans une collection spécifique, et à décider "arbitrairement" que le premier représentera les millier, le deuxième représentera les centaines, le troisième représentera les dizaines et le dernier représentera les unités.

              Par facilité, nous serions bien inspirés de créer une énumération pour représenter cette décision.  Elle prendrait sans doute une forme proche de

              enum position{
              	thosands, // == 0
              	hundreds, // == 1
              	tens,     // == 2
              	units,    // == 3
              	MAX       // parce que les tableaux sont indexés
                                // à partir de 0, correspond au nombre
                                // d'éléments du tableau
              };

              Et nous pourrions l'utiliser pour définir le type de donnée particulier dont on a besoin pour représenter notre "collection de chiffres" sous une forme proche de

              // !!! nécessite l'inclusion du fichier 
              using SubValues = std::array<int, MAX>;

              Ensuite, nous devons prévoir les fonctions qui s'occuperont de tout pour nous. La première dont nous avons besoin est celle qui s'occupera de subdiviser le nombre d'origine, et qui pourrait ressembler à quelque chose comme

              SubValues divide(int origin){
                  SubValues subValues;
                  size_t pos=units;
                  while(origin>0){
                      // je vais te laisser réfléchir à comment faire,
                      // ce serait trop facile autrement    
                  }
                  return subValues;
              }

              La deuxième fonction dont nous aurons besoin, ce sera celle qui nous permettra d'afficher les différents chiffres obtenus.  Elle pourrait ressembler à quelque chose comme

              void printCiffers(SubValues const & values){
                  //!!! nécessite l'inclusion du fichier 
                  static const std::array<std::string, MAX> str{"milliers","centaines,", "dizaines", "unités"};
                  size_t pos{thosands};
                  while(pos< MAX){
                      std::cout<<str[pos]<<" : "<<values[pos]<<"\n";
                      ++pos;
                  }
              }

              Mais ce n'est bien sur qu'un exemple, elle pourrait être très largement modifiée ;)

              La troisième fonction dont nous avons besoin, ce sera celle qui pourra crypter les données.  Elle pourrait prendre une forme proche de

              void encrypt(SubValues & value){
                  for(auto & it : value){
                      // calculer la nouvelle valeur de it ... cela les 
                      // modifiera automatiquement dans notre collection
                      // d'origine
                  }
                  // intervertir miliiers et dizaines
                  // intervertir centaines et unités
              }

               Comme je veux pouvoir voir le nombre qui résulte de l'encryption, je vais tout de suite créer la fonction qui me recrée un nombre sur base des quatre valeurs dont je dispose.  Elle pourrait prendre une forme proche de

              int merge(SubValues const & value){
              	int result{0};
              	for(size_t pos{thosands}; pos<MAX;++pos){
              		result+= value[pos];
              		if(pos!=units)
              			result *=10;
              	}
              	return result;
              }

              Selon la forme que pourrait prendre la transmission, elle pourrait d'ailleurs très bien servir à cet effet aussi ;)

              Mais, comme nous ne savons rien de la méthode de transmission, nous ferons "comme si" elle était inutile dans ce cas là...

              La fonction suivante dont nous avons besoin est celle qui nous permettra de décrypter les données. Elle pourrait prendre la forme de

              void decrypt(SubValues & value){
                  // intervertir milliers et dizaines
                  // intervertir centaiens et unités
                  for(auto & it : value){
                      // rétablir la valeur d'origine pour it ...
                      // cela modifiera notre collection d'origine
                  }
              }

              Et il ne nous manque plus que la fonction qui générera les nombres aléatoires.  Elle pourrait prendre la forme de

              int randomValue(){
                  // !!! nécessite l'inclusion du fichier <random>
                  static std::random_device rd;  
                  static std::mt19937 gen(rd()); 
                  static std::uniform_int_distribution<> dis(1, 9999);
                  return dis(gen);
              }

              Une fois toutes ces fonctions créées, nous devrons, bien sur, mettre tout cela "en musique" dans la fonction principale.  Elle pourrait prendre une forme proche de

              int main(){
              	int value= randomValue();
              	std::cout<<"original value :"<<value<<"\n";
              	auto sub = divide(value);
              	printCiffers(sub);
              	encrypt(sub);
              	std::cout<<"After encryption :\n";
              	printCiffers(sub);
              	std::cout<<"Or : "<<merge(sub)<<"\n";
              	decrypt(sub);
              	std::cout<<"final result = "<<merge(sub)<<"\n";
              	return 0;
              }
              

              qui est -- ici -- écrite de manière à nous montrer toutes les étapes par lesquelles nous passons lors du cryptage et du décryptage des données ;)


              Merci pour ta réponse plus que complète mais je ne comprends pas grand chose, j'ai commencé le C++ il y a 1 mois avec mon BTS mais je n'y avais jamais touché avant.. A quoi correspond toutes ces choses?

              "

              using SubValues = std::array<int, MAX>;"

               "size_t"

              "auto"

              Comment inclure mon fichier?

              Nous avons à disposition Les variables, les tests, les boucles et les tableaux.. Je pense que tu comprendras que je ne sais pas trop quoi faire de ce que tu m'as donné.

              • Partager sur Facebook
              • Partager sur Twitter
                9 octobre 2018 à 10:42:07

                Alors,

                using SubValues = std::array<int, MAX>; définit un alias de type (comme typedef pourrait en créer un, mais à la mode du C++11 ou ultérieur) d'un std::array (un tableau dont la taille est définie à la compilation, également apparu en C++11) de int qui contient MAX éléments (MAX étant égal à 4, de par l'énumération)

                size_t est un alias de type sur "le type entier non signé" qui permet de représenter la taille de n'importe quelle collection d'éléments:

                Toutes les collections de la bibliothèque standard permettent de connaître le nombre d'éléments qui la composent au travers d'une fonction membre size().

                Cette fonction renvoie systématiquement une valeur sous de type size_t, et c'est -- par défaut -- également le type qu'il est préférable d'utiliser lorsque l'on veut accéder aux indice d'un tableau, car c'est le seul type qui puisse nous donner "toutes les garanties" que nous pourrons -- effectivement -- accéder à tous les éléments qu'il contient.

                auto est également apparu ne C++11 et demande au compilateur de définir lui-même le type d'une donnée, sur base de l'expression qui lui est fournie : for(auto & it : value) crée une boucle "for" qui va utiliser la variable it, qui sera à chaque fois une référence vers une donnée "du type de donnée des éléments contenus par value" pour parcourir l'ensemble des éléments contenus par value.

                De cette manière, même si je décidais de modifier le type des éléments de value (pour utiliser un long ou un short au lieu d'un int, par exemple), la boucle pourrait continuer à fonctionner sans que je n'ai besoin d'aller changer quoi que ce soit; du moins, aussi longtemps que le type des données contenue par value permettra les mêmes actions que le type d'origine

                hugomocq a écrit:

                Comment inclure mon fichier?

                Si tu fais références aux commentaires "nécessite l'inclusion du fichier <array>", "nécessite l'inclusion du fichier <string>" ou "nécessite l'inclusion du fichier <random>", exactement de la même manière que tu inclut <iostream> pour pouvoir faire appel à stc::cout : "#include <nom_du_fichier_requis> ", au tout début de ton fichier d'implémentation (*.cpp)

                Si tu demandes comment rendre toutes ces fonctions disponibles, tu peux te contenter de les mettre, dans l'ordre dans lequel je te les ai présentées, avant la fonction main() dans ton fichier d'implémentation, mais après l'inclusion des fichiers d'en-tête nécessaires

                -
                Edité par koala01 9 octobre 2018 à 10:42:58

                • 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
                  9 octobre 2018 à 10:56:37

                  Merci beaucoup, je vais essayer de le faire grâce à ton aide mais je ne garantis pas y arriver étant donné que nous n'avons vu en cours que les bases (tableaux,tests,boucles et définition d'une variable).

                  D'ailleurs,

                  enum position{
                      thosands, // == 0
                      hundreds, // == 1
                      tens,     // == 2
                      units,    // == 3
                      MAX       // parce que les tableaux sont indexés
                                    // à partir de 0, correspond au nombre
                                    // d'éléments du tableau
                  };

                  où dois-je le placer?

                  -
                  Edité par hugomocq 9 octobre 2018 à 11:00:23

                  • Partager sur Facebook
                  • Partager sur Twitter
                    9 octobre 2018 à 12:27:50

                    J'ai tout donné dans l'ordre logique qu'il faudra respecter dans ton fichier d'implémentation.  Il n'y a que l'inclusion des fichiers d'en-tête qui doive venir avant tout le reste:

                    Si tu observe bien, on utilise la valeur énumérée MAX pour la définition de l'alias de type Subvalues, puis, on utilise -- d'une manière ou d'une autre -- SubValues et les différentes valeurs énumérées dans la plupart des fonctions.

                    Or, le compilateur va "lire" un code exactement de la même manière que tu lirait un roman : quand il est à la ligne dix d'un code, connait tout ce qu'il a croisé dans les neuf première lignes, mais il ne sait rien de ce qui se passe à la ligne onze ou à la lignge douze...

                    Et s'il croise à la ligne dix, un identifiant qui ne lui est expliqué qu'à la ligne douze, il ne sera pas content, parce qu'il ne connaitra pas l'identifient en question.  Il va donc émettre une erreur avant d'arrêter de travailler.

                    Sachant tout cela, tu devrais pouvoir recréer le code dans l'ordre qui sera "suffisamment logique" que pour que le compilateur connaisse tout ce qu'il doit connaitre à tout moment ;)

                    • 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
                      9 octobre 2018 à 15:08:06

                      hello,

                      Avec seulement ces "connaissances de base" dont tu nous as parlé et un peu de réflexion tu peux déjà réussir à découper ton nombre. ^^

                      Tu as probablement dû voir les opérations arithmétiques sur les variables, du coup tu dois savoir que parmi ces opérations, tu en as 2 qui te seront utiles:

                      • la division, qui te permet de retrouver le résultat de la division (525/100 = 5)
                      • le modulo, qui te permet de retrouver le reste de la division (525%100 = 25)

                      En utilisant les bonnes opérations tu peux en quelques lignes récupérer les infos qui te seront utiles (je te laisse écrire le code et utiliser les opérations qui vont bien…)

                      • Partager sur Facebook
                      • Partager sur Twitter

                      Cryptage C++

                      × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                      × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                      • Editeur
                      • Markdown