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 :

Évaluation pour progresser


Sujet :

C++

  1. #1
    Membre du Club
    Profil pro
    Étudiant
    Inscrit en
    Mai 2010
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2010
    Messages : 25
    Points : 41
    Points
    41
    Par défaut Évaluation pour progresser
    Bonjour,
    Je viens de terminer une exercice ayant pour but de mettre en place un système de cryptage/décryptage en utilisant le nombre de César.

    Mon application fonctionne, mais je voudrais savoir si il y a des problèmes (bogues, problème de style, réinventer la roue, etc.) que je n'ai pas remarqués ou, plus simplement, si il y a des choses que j'aurais du faire carrément autrement. Le but est simplement de m'améliorer et de tenter d'avoir le code le plus robuste possible.

    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
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    #include <iostream>
    #include <algorithm>
    #include <sstream>
    #include <locale>
    #include <array>
    #include <string>
    #include <cassert>
     
    std::string encrypt(int shift, std::string word);
    std::string decrypt(int shift, std::string word);
     
    int main()
    {
    	int shift = 5;
    	std::stringstream sentence("Hello World ABCDEFgHIJKLmNOPqRSTUVWXYZ");
    	std::stringstream encrypted_sentence;
    	std::stringstream decrypted_sentence;
     
     
    	while(!sentence.eof())
    	{
    		std::string temp;
    		sentence >> temp;
    		encrypted_sentence << encrypt(shift, temp) << " ";
    	}
     
    	while(!encrypted_sentence.eof())
    	{
    		std::string temp;
    		encrypted_sentence >> temp;
    		decrypted_sentence << decrypt(shift, temp) << " ";
    	}
     
    	std::cout << sentence.str() << std::endl;
    	std::cout << encrypted_sentence.str() << std::endl;
    	std::cout << decrypted_sentence.str() << std::endl;
    }
     
    std::string encrypt(int shift, std::string word)
    {
    	static const std::array<char, 26> letters = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};
    	if(shift != 0)
    	{
    		for(std::string::iterator it = word.begin(); it != word.end(); ++it)
    		{
    			bool was_lower = false;
    			if(std::islower(*it))
    			{
    				was_lower = true;
    				*it = std::toupper(*it);
    			}
     
    			std::array<char, 26>::const_iterator new_character = std::find(letters.begin(), letters.end(), *it);
     
    			assert(new_character != letters.end());
     
    			if(shift > 0)
    			{
    				for(int i = 0; i < shift; ++i)
    				{
    					++new_character;
     
    					if(new_character == letters.end())
    						new_character = letters.begin();
    				}
    			}
    			else
    			{
    				for(int i = 0; i > shift; --i)
    				{
    					if(new_character == letters.begin())
    						new_character = letters.end();
     
    					--new_character;
    				}
    			}
     
    			if(was_lower)
    				*it = std::tolower(*new_character);
    			else
    				*it = *new_character;
    		}
    	}
     
    	return word;
    }
     
    std::string decrypt(int shift, std::string word)
    {
    	return encrypt(-shift, word);
    }
    Pour ce qui est de l'algorithme que j'utilise, je parcours chaque lettre du mot à crypter et, pour chacune d'entre elles, je recherche la position correspondante dans l'alphabet et va chercher la lettre décalée selon la valeur de décalage reçue en paramètre. Une fois la nouvelle lettre trouvée, je remplace la lettre d'origine et passe au caractère suivant.

    PS: Bien que ce ne soit pas vraiment important, puisque je tente de conserver un code multiplatforme, sachez que je compile avec GCC 4.5.2 sous GNU/Linux.

  2. #2
    Membre expérimenté
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2011
    Messages
    576
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2011
    Messages : 576
    Points : 1 528
    Points
    1 528
    Par défaut
    Salut,

    C'est très bien de vouloir s'améliorer

    J'ai quelques remarque sur la forme, pour le fond, voir si l'algo est bon, rapide, etc... je n'ai pas trop le temps de regarder.

    Commentaires:
    - Pour une fonction, toujours préciser à quoi servent les paramètres et ce qu'elle fait (même si là c'est évident, c'est toujours bon de prendre les bonnes habitudes dès le début . Tu peux utiliser une syntaxe à la doxygen par exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    /**
     * Encrypt la chaine
     * @param shift Decalage a appliquer
     * @param word Chaine a encrypter
     * @return chaine encrypte
     */
    std::string encrypt(int shift, std::string word);
    - Dans l'algo, préciser les points clef, ce que fait tel ou tel bloc de code, etc... sans paraphraser le code non plus (genre "je met l'alphabet dans la variable letters" ça ne sert pas à grand chose ^^)

    Passer les param. par référence plutôt que par copie:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    std::string encrypt(int shift, const std::string& word);
    Ca évite de recopier la string lors du passage en paramètre. De même, tu peux passer la valeur de retour par référence au lieu de la retourner, cela évite aussi une copir lors du retour de la fonction:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    void encrypt(int shift, const std::string& word, std::string& out);
    Un peu délicat comme notion au début mais ça viendra.

    Sinon les nom de variable sont bien choisi et le code n'est pas trop fouilli.
    La perfection est atteinte, non pas lorsqu’il n’y a plus rien à ajouter, mais lorsqu’il n’y a plus rien à retirer. - Antoine de Saint-Exupéry

  3. #3
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 705
    Points
    2 705
    Par défaut
    Citation Envoyé par authchir Voir le message
    cryptage/décryptage
    -> chiffrage/déchiffrage

    Sinon, extrais de tes boucles tes créations de string (lignes 22 & 29).
    La création d'un objet coûte cher.

  4. #4
    Membre chevronné
    Avatar de Joel F
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Septembre 2002
    Messages
    918
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur en informatique
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2002
    Messages : 918
    Points : 1 921
    Points
    1 921
    Par défaut
    Citation Envoyé par pyros Voir le message
    Passer les param. par référence plutôt que par copie:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    std::string encrypt(int shift, const std::string& word);
    Ca évite de recopier la string lors du passage en paramètre. De même, tu peux passer la valeur de retour par référence au lieu de la retourner, cela évite aussi une copir lors du retour de la fonction:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    void encrypt(int shift, const std::string& word, std::string& out);

    Non, via la copy-elision et les mecanismes d'optimisations des valeur de retour, renvoyer une instance est aussi voir plus rapide que de pourrir le prototype avec une reference.

    http://cpp-next.com/archive/2009/08/...pass-by-value/

  5. #5
    Membre expérimenté
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2011
    Messages
    576
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2011
    Messages : 576
    Points : 1 528
    Points
    1 528
    Par défaut
    Cool, je connaissais pas cette optim
    La perfection est atteinte, non pas lorsqu’il n’y a plus rien à ajouter, mais lorsqu’il n’y a plus rien à retirer. - Antoine de Saint-Exupéry

  6. #6
    Membre du Club
    Profil pro
    Étudiant
    Inscrit en
    Mai 2010
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2010
    Messages : 25
    Points : 41
    Points
    41
    Par défaut
    Hé bien d'abord, merci de vos commentaires.

    Citation Envoyé par pyros Voir le message
    Pour une fonction, toujours préciser à quoi servent les paramètres et ce qu'elle fait (même si là c'est évident, c'est toujours bon de prendre les bonnes habitudes dès le début . Tu peux utiliser une syntaxe à la doxygen...
    Oui, je connais un peu Doxygen et c'est vrai que ça doit être très pratique pour travailler sur un gros programme ou une grosse bibliothèque. Jusqu'ici, je n'avais jamais prit l'habitude d'écrire systématiquement ce genre de commentaires...

    Citation Envoyé par pyros Voir le message
    Dans l'algo, préciser les points clef, ce que fait tel ou tel bloc de code, etc...
    C'est une bonne idée. Pour l'instant, la fonction me parait évidente, mais je l'aurai probablement oublié dans un ou deux mois et cela pourrais éviter d'avoir à relire et recomprendre le code dans son entièreté. Je penserais à quelque chose comme ça:

    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
    52
    53
    54
    55
    std::string encrypt(int shift, std::string word)
    {
    	static const std::array<char, 26> letters = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};
     
    	// No job to do if shift is zero
    	if(shift != 0)
    	{
    		// Replace each character by it's corresponding encrypt character
    		for(std::string::iterator it = word.begin(); it != word.end(); ++it)
    		{
    			// We must work on upper case letters
    			bool was_lower = false;
    			if(std::islower(*it))
    			{
    				was_lower = true;
    				*it = std::toupper(*it);
    			}
     
    			std::array<char, 26>::const_iterator new_character = std::find(letters.begin(), letters.end(), *it);
     
    			assert(new_character != letters.end());
     
    			if(shift > 0)
    			{
    				// Increment until we find the encrypt character
    				for(int i = 0; i < shift; ++i)
    				{
    					++new_character;
     
    					if(new_character == letters.end())
    						new_character = letters.begin();
    				}
    			}
    			else
    			{
    				// Decrement until we find the encrypt character
    				for(int i = 0; i > shift; --i)
    				{
    					if(new_character == letters.begin())
    						new_character = letters.end();
     
    					--new_character;
    				}
    			}
     
    			// Replace the new character to the initial upper/lower case
    			if(was_lower)
    				*it = std::tolower(*new_character);
    			else
    				*it = *new_character;
    		}
    	}
     
    	return word;
    }
    Je remarque que ce sont surtout les boucles qui sont pratique à commenter...

    Citation Envoyé par oodini Voir le message
    Sinon, extrais de tes boucles tes créations de string (lignes 22 & 29).
    La création d'un objet coûte cher.
    Mais si l'initialisation est en dehors de la boucle, la variable vivra alors jusqu'à la fin de la fonction. Nous aurons donc à subir le poid de celle-ci alors qu'elle ne sert plus à rien.

    J'avoue cependant qu'un std::string ne doit pas peser très lourd. Dans ce genre de cas, est-il plus commun de choisir la vitesse d'exécution (en initialisant la variable à l'extérieur) ou bien l'utilisation de mémoire vive (en initialisant la variable à l'interrieur)?

    Pour ce qui est du passage par référence ou par copie, j'ajouterais que je souhaite que la variable de l'utilisateur reste inchangée et que je dois modifier ma copie de la variable pour la chiffrer. C'est pour cette raison que j'avais choisie de la recevoir par copie. Par contre, je suis heureux d'apprendre que les compilateurs sont à même d'optimiser le retour par copie d'une variable reçue par copie.

  7. #7
    Membre éclairé Avatar de PadawanDuDelphi
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2006
    Messages
    678
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : Bâtiment

    Informations forums :
    Inscription : Août 2006
    Messages : 678
    Points : 717
    Points
    717
    Par défaut
    Salut,

    is si l'initialisation est en dehors de la boucle, la variable vivra alors jusqu'à la fin de la fonction. Nous aurons donc à subir le poid de celle-ci alors qu'elle ne sert plus à rien.

    J'avoue cependant qu'un std::string ne doit pas peser très lourd. Dans ce genre de cas, est-il plus commun de choisir la vitesse d'exécution (en initialisant la variable à l'extérieur) ou bien l'utilisation de mémoire vive (en initialisant la variable à l'interrieur)?
    Ca dépend de ce que tu as besoin...Dans ton cas l'important c'est la vitesse d'execution, donc il vaut mieux créer tes objets à l'extérieur de tes boucles, à moins d'être vraiment très juste au niveau de la mémoire vive (enfin un string ça fait pas non plus 2Go).

    Pour ce qui est du passage par référence ou par copie, j'ajouterais que je souhaite que la variable de l'utilisateur reste inchangée et que je dois modifier ma copie de la variable pour la chiffrer. C'est pour cette raison que j'avais choisie de la recevoir par copie. Par contre, je suis heureux d'apprendre que les compilateurs sont à même d'optimiser le retour par copie d'une variable reçue par copie.
    Avec le mot clef const le compilateur s'assurera que ta fonction ne modifiera pas ta variable. En outre c'est plus explicite et plus clair ainsi (on sait que ce paramètre est constant).
    For crying out loud !

  8. #8
    Membre expérimenté
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2011
    Messages
    576
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2011
    Messages : 576
    Points : 1 528
    Points
    1 528
    Par défaut
    Pour ma part, il est très important de mettre un petit commentaire sur les boucles en c++. Autant dans certains langage, elle sont évidentes (dans beaucoup de langage plus haut niveau (C#, python, ruby, etc...) tu peux écrire une boucle "for each letter in alphabet" par exemple), autant en c++ c'est beaucoup moins évident. Et encore moins avec des itérateur (même si les itérateur c'est bien !).
    Donc un petit commentaire comme tu l'as fait est très appréciable.

    Ensuite, j'ai tendance à traiter les cas particuliers des fonctions au début, pour laisser place au vrai algo. Donc j'écrirais ta fonction encrypt comme ceci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    std::string encrypt(int shift, std::string word)
    {
    	static const std::array<char, 26> letters = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};
     
    	// No job to do if shift is zero
    	if(shift == 0)
    	    return;
     
    ...
    Ca permet de ne pas se trainer l'indentation du if tout le long de la fonction. Mais certaines personne n'aime pas mettre des return au milieu du code (ça le rend en effet un peu moins clair). Donc c'est une question de gout.

    Pour finir, déclarer le string dans ou hors de la boucle, c'est commencer à faire de la micro-optimisation (google est ton amis pour plus de précision). Et ça, c'est le mal !!!, surtout lorsqu'on débute. Déclare ta variable là ou tu pense qu'elle vas bien. Le compilo optimisera sûrement tout ça de lui même. Cette remarque s'applique aussi sur passer par référence ou par copie. Si tu ne sais pas quoi faire, fait ce qui te semble le plus clair et le plus propre, et fait confiance au compilo pour faire ce qu'il faut.
    La perfection est atteinte, non pas lorsqu’il n’y a plus rien à ajouter, mais lorsqu’il n’y a plus rien à retirer. - Antoine de Saint-Exupéry

  9. #9
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 705
    Points
    2 705
    Par défaut
    Citation Envoyé par authchir Voir le message
    Mais si l'initialisation est en dehors de la boucle, la variable vivra alors jusqu'à la fin de la fonction. Nous aurons donc à subir le poid de celle-ci alors qu'elle ne sert plus à rien.
    Si cela te pose vraiment un problème, tu peux ajouter un groupe d'accolade :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    ...
    {
        std::string pouet;
     
        for (...)
        {
            ...
        }
    }
    ...
    Citation Envoyé par authchir Voir le message
    J'avoue cependant qu'un std::string ne doit pas peser très lourd. Dans ce genre de cas, est-il plus commun de choisir la vitesse d'exécution (en initialisant la variable à l'extérieur) ou bien l'utilisation de mémoire vive (en initialisant la variable à l'intérieur) ?
    Il est très rare que la mémoire vive soit à ce point prioritaire par rapport à la vitesse d'exécution (compte tenu de la place occupée par le string qui nous occupe ici).
    Et souviens-toi : toujours éviter la construction inutile d'objet. Cela occasionne appel de fonction et création de membres. Multiplié par le nombre d’exécution de la boucle.

    D'autant plus que dès que tu sors de la boucle, il faut tout refaire dans le sens inverse...

  10. #10
    Membre du Club
    Profil pro
    Étudiant
    Inscrit en
    Mai 2010
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2010
    Messages : 25
    Points : 41
    Points
    41
    Par défaut
    Hé bien merci pour vos réponses, je vais partir à la recherche d'autres exercices.

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

Discussions similaires

  1. Réponses: 4
    Dernier message: 03/07/2010, 15h18
  2. Plugin Eclipse pour Progress
    Par remyv87 dans le forum Eclipse
    Réponses: 3
    Dernier message: 03/07/2008, 15h55
  3. Fonction d'évaluation pour algo génétique.
    Par Trap D dans le forum Intelligence artificielle
    Réponses: 16
    Dernier message: 14/04/2008, 10h34
  4. Livre PHP pour progresser rapidement
    Par theflagada dans le forum Mode d'emploi & aide aux nouveaux
    Réponses: 2
    Dernier message: 28/05/2007, 02h15
  5. Réponses: 8
    Dernier message: 29/06/2006, 14h22

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