Bien programmer en langage C
Vous souhaitez réagir à ce message ? Créez un compte en quelques clics ou connectez-vous pour continuer.
-15%
Le deal à ne pas rater :
(Adhérents) LEGO® Icons 10318 Le Concorde
169.99 € 199.99 €
Voir le deal

Cryptage Carré de Polybe...

2 participants

Aller en bas

Cryptage Carré de Polybe... Empty Cryptage Carré de Polybe...

Message  azerty Lun 17 Nov 2008 - 23:31

Bon, je sais pas si cette section est le plus adaptée, mais je poste mon code... Si vous pouviez m'aider à l'optimiser, l'améliorer, et me dire si la mise en forme (indentation etc.) est bonne ?
Code:

/*  main.c  */

#include "polybe.h"
#include <stdio.h>
#define MAX 1000

int main(void)
{
    char s_phraseACrypter[MAX];
    char s_phraseCryptee[MAX];
    int i;

    printf("Entrez la phrase a crypter:\n");
    fgets(s_phraseACrypter, MAX, stdin);

    crypterPolybe(s_phraseACrypter, s_phraseCryptee);

    printf("Voici la phrase cryptee:\n");

    for (i = 0 ; s_phraseACrypter[i] ; i++)
    {
            printf("%d ", s_phraseCryptee[i]);
    }

    printf("\n");

    return 0;
}

Code:

/*  polybe.c  */

#include "polybe.h"
#include <string.h>

void crypterPolybe(char *s_phraseACrypter, char *s_phraseCryptee)
{
    int i = 0;

    char *p = strchr(s_phraseACrypter, '\n');

    if (p != NULL)
    {
        *p = 0;
    }


    do
    {

        int c = s_phraseACrypter[i] - 'a';

        if (s_phraseACrypter[i] >= 'a' && s_phraseACrypter[i] <= 'v')
        {
            s_phraseCryptee[i] = c + 11 + 5*(c/5);
        }

        else if (s_phraseACrypter[i] >= 'w' && s_phraseACrypter[i] <= 'z')
        {
            c--;
            s_phraseCryptee[i] = c + 11 + 5*(c/5);
        }

        else
        {
            s_phraseCryptee[i] = 0;
        }

        i++;

    } while (s_phraseACrypter[i]);
}


Code:

#ifndef H_POLYBE
#define H_POLYBE

/* polybe.h */

void crypterPolybe(char *, char *);

#endif  /*  guard  */


Dernière édition par -ed- le Mar 18 Nov 2008 - 11:52, édité 1 fois (Raison : Mise en forme)

azerty
Bavard
Bavard

Messages : 15
Date d'inscription : 17/11/2008

Revenir en haut Aller en bas

Cryptage Carré de Polybe... Empty Re: Cryptage Carré de Polybe...

Message  -ed- Mar 18 Nov 2008 - 11:53

Exclamation Il manque le sujet de l'exercice (relire la règle de cette section).

Présentation

- C'est très bien d'avoir nommé les fichiers.
- Indentation logique, mais un peu irrégulière (parfois 4, parfois 8...).
- Quelques lignes vides inutiles
- Pour un do-while, c'est :
Code:

  do
  {
      /* actions */
  }
  while ();
- Dans les commentaires, ne laisser qu'un espace après /* et avant */ :
Code:
/* guard */
Je suggère l'usage d'un indenteur automatique comme celui de Code::Blocks (Mode 'ANSI')

Codage

/* main.c */

- Avec gcc en mode sévère, la compilation se passe sans avertissement.
- J'apprécie l'usage du préfixe s_ pour nommer les chaines.
- Contrairement aux idées reçues, l'usage systématique d'une constante symbolique n'est pas forcément une bonne chose. En effet, par son caractère 'global' (définie hors de toute fonction), elle peut créer un dépendance mal venue et faire oublier de passer un paramètre 'taille' à une fonction, ce qui peut être désastreux dans certaines applications... Je vois 2 solutions à cette question :

1 - La définition du tableau est le bon endroit pour définir la valeur de la constante
En effet, ce qui compte, c'est que la définition soit unique et placée dans un endroit stratégique.
Code:

  char s_phraseACrypter[1000];
  char s_phraseCryptee[sizeof s_phraseACrypter];
...
  fgets (s_phraseACrypter, sizeof s_phraseACrypter, stdin);
Pas très esthétique. Le passage en wchar_t n'est pas très aisé...

(pourrait être facilité par l'usage de la macro NELEM())
Code:

#define NELEM(a) (sizeof(a)/sizeof*(a))
...
  char s_phraseACrypter[1000];
  char s_phraseCryptee[NELEM (s_phraseACrypter)];
...
  fgets (s_phraseACrypter, NELEM (s_phraseACrypter), stdin);

2 - Mise en place de la stratégie de réduction de la portée des constantes, objets et fonctions :
On peut simuler une définition 'locale' de la macro grâce à une astuce syntaxique peu orthodoxe, mais correcte et efficace :
Code:

int main (void)
{
#define MAX 1000
  char s_phraseACrypter[MAX];
  char s_phraseCryptee[MAX];
...
  printf ("Entrez la phrase a crypter:\n");
  fgets (s_phraseACrypter, MAX, stdin);
...
  return 0;
#undef MAX
}
Ce qui nous ramène quasiment au code d'origine.

Dans le même esprit, et s'agissant d'une constante 'entier', on peut utiliser enum :
Code:

int main (void)
{
  enum {MAX = 1000};
  char s_phraseACrypter[MAX];
  char s_phraseCryptee[MAX];
...
  printf ("Entrez la phrase a crypter:\n");
  fgets (s_phraseACrypter, MAX, stdin);
...
  return 0;
}
Cette fois, c'est le langage C qui fournit officiellement la réduction de la portée (définition d'un enum dans un bloc)

L'effet n'est pas spectaculaire ici, mais dans d'autres circonstances, il aurait pu révéler des dépendances indésirables...

- Je suis étonné par cette séquence :
Code:

  fgets (s_phraseACrypter, MAX, stdin);

  crypterPolybe (s_phraseACrypter, s_phraseCryptee);
En effet, la 'phrase saisie' ne devrait pas comporter de '\n'. Il serait donc logique de faire le nettoyage (et la purge de stdin, par la même occasion) avant de passer la phrase au traitement.
Code:

  fgets (s_phraseACrypter, MAX, stdin);
  fclean (s_phraseACrypter, stdin);

  crypterPolybe (s_phraseACrypter, s_phraseCryptee);
Le code de fclean() comporte la détection du '\n', son élimination si présent, sinon, la purge du flux :
Code:

#include <stdio.h>
#include <string.h>

void fclean (char *line, FILE * fp)
{
  char *p = strchr (line, '\n');
  if (p != NULL)
  {
      *p = 0;
  }
  else
  {
      int c;
      while ((c = fgetc (fp)) != '\n' && c != EOF)
      {
      }
  }
}
Vu les services rendus tous les jours par cette fonction, il y a bien longtemps qu'elle a été intégrée à ma bibliothèque personnelle...

Toujours dans le cadre de la politique de réduction de la portée des objets, je suggère de limiter la portée de i au strict minimum :
Code:

int mainj (void)
{
  ...
  {
      int i;
      for (i = 0; s_phraseACrypter[i]; i++)
      {
        printf ("%d ", s_phraseCryptee[i]);
      }
  }
  ...
  return 0;
}
On voit tout de suite que ça fait apparaitre un bloc fonctionnel ("afficher la phrase codée") qui ne demande qu'à être transformé en fonction... Cette politique favorise la modularisation du code...

Par contre, je m'interroge sur le code lui même. Bien que ce ne soit pas très lisible,

(je propose : )
Code:
      for (i = 0; s_phraseACrypter[i] != 0; i++)
il semblerait que la fonction d'affichage considère que la chaine cryptée est une chaine de caractères comme les autres, c'est à dire terminée par un 0. Est-il bien certain que le codage ne génère pas de 0 ?

Je suis d'autant plus surpris par ce résultat ...
Code:

Entrez la phrase a crypter:
Hello world
Voici la phrase cryptee:
0 15 32 32 35 0 52 35 43 32 14

Process returned 0 (0x0)  execution time : 4.204 s
Press any key to continue.
... qui parait impossible ! (2 zéros dans la chaine ? Pourquoi la boucle ne s'est pas arrêtée ? Mystère...)

Ah, j'ai compris ! La condition d'arrêt est sur la chaine saisie ! C'est tordu ! Je suggère que la fonction de cryptage renvoie la longueur de la chaine cryptée et que celle-ci soit utilisée pour l'affichage :
Code:

  {
      int n = crypterPolybe (s_phraseACrypter, s_phraseCryptee);

      printf ("Voici la phrase cryptee:\n");
      {
        int i;
        for (i = 0; i < n; i++)
        {
            printf ("%d ", s_phraseCryptee[i]);
        }
      }
      printf ("\n");
  }
ce qui entraine une légère modification de l'interface de la fonction :

/* polybe.h */

Code:
int crypterPolybe (char *, char *);
Au fait, c'est pas très lisible ça. On aimerait que ce code soit auto-documenté en mettant des noms de paramètres en clair :
Code:
int crypterPolybe (char *s_acoder, char *s_codee);
et il est fort probable (et fortement souhaitable) que la chaine originale ne soit pas modifiée :
Code:
int crypterPolybe (char const *s_acoder, char *s_codee);
enfin, l'usage veut que dans ce type de fonciton avec une entrée et une sortie, on respecte la logique de l'opérateur d'affectation x = y ou x <- y en langage algorithmique, c'est à dire que la destination est à la gauche de la source. :
Code:
int crypterPolybe (char *s_codee, char const *s_acoder);
Exclamation Attention aux conséquences d'une telle modification sur le code source. Elles peuvent être mortelles ! Ne le faire que si les modifications entrainées sont faibles et localisées. Sinon, penser à cette meilleure conception pour la prochaine fois...

Ici, pas de problèmes, je fais la modification.

/* polybe.c */
- Très bien le #include "polybe.h" en 1er include.
- La chaine ayant été nettoyée, on peut supprimer ceci :
Code:

  char *p = strchr (s_phraseACrypter, '\n');

  if (p != NULL)
  {
      *p = 0;
  }
- Attention au do-while qui impose au moins un traitement. Que se passe-t-il si la chaine est vide ?
Code:

Entrez la phrase a crypter:

Voici la phrase cryptee:
0

Process returned 0 (0x0)  execution time : 1.429 s
Press any key to continue.
Est-ce le résultat attendu ? (Je rappelle que tu n'as pas publié l'énoncé).

- Attention, ce code n'est pas portable :
Code:
      int c = s_phraseACrypter[i] - 'a';
en effet, il fait l'hypothèse que les caractères sont consécutifs, ce qui n'est pas forcément vrai. De plus, que se passe-t-il avec les majuscules et les accentuées ?

Je n'irais pas plus loin pour le moment, car ce problème est à résoudre avant tout.

Voici le code actuel :
Code:

/*  main.c  */

#include "polybe.h"
#include <stdio.h>
#include <string.h>

static void fclean (char *line, FILE * fp)
{
  char *p = strchr (line, '\n');
  if (p != NULL)
  {
      *p = 0;
  }
  else
  {
      int c;
      while ((c = fgetc (fp)) != '\n' && c != EOF)
      {
      }
  }
}

static void afficherCryptee (char const *s_phraseCryptee, int n)
{
  int i;
  printf ("Voici la phrase cryptee:\n");
  for (i = 0; i < n; i++)
  {
      printf ("%d ", s_phraseCryptee[i]);
  }
  printf ("\n");
}

int main (void)
{
  enum
  { MAX = 1000 };
  char s_phraseACrypter[MAX];
  char s_phraseCryptee[MAX];

  printf ("Entrez la phrase a crypter:\n");
  fgets (s_phraseACrypter, MAX, stdin);
  fclean (s_phraseACrypter, stdin);

  {
      int n = crypterPolybe (s_phraseCryptee, s_phraseACrypter);
      afficherCryptee (s_phraseCryptee, n);
  }

  return 0;
}
Code:

#ifndef H_POLYBE
#define H_POLYBE

/* polybe.h */

int crypterPolybe (char *s_codee, char const *s_acoder);

#endif /* guard */
Code:

/*  polybe.c  */

#include "polybe.h"

int crypterPolybe (char *s_phraseCryptee, char const *s_phraseACrypter)
{
  int i = 0;

  do
  {
      int c = s_phraseACrypter[i] - 'a';

      if (s_phraseACrypter[i] >= 'a' && s_phraseACrypter[i] <= 'v')
      {
        s_phraseCryptee[i] = c + 11 + 5 * (c / 5);
      }

      else if (s_phraseACrypter[i] >= 'w' && s_phraseACrypter[i] <= 'z')
      {
        c--;
        s_phraseCryptee[i] = c + 11 + 5 * (c / 5);
      }

      else
      {
        s_phraseCryptee[i] = 0;
      }
      i++;
  }
  while (s_phraseACrypter[i]);

  return i;
}
Si tu proposes une nouvelle version de ton code, je te demande de repartir ce cette version, car je ne vais pas refaire les modification que j'ai apportées...
-ed-
-ed-
Admin
Admin

Messages : 290
Date d'inscription : 26/05/2008
Age : 67
Localisation : Paris 14eme arrondissement (75, France)

http://bien-programmer.fr

Revenir en haut Aller en bas

Cryptage Carré de Polybe... Empty Bien reçu !

Message  azerty Ven 21 Nov 2008 - 12:45

Un grand merci à toi !
Il n'y avait pas d'énoncé particulier, c'est pour mes TPE de 1ère SI (sujet: cryptographie, problématique à trouver). Il s'agissait juste de crypter avec le carré de Polybe, avec un code le mieux possible. Donc j'applique tes modifications et celles conseillées par d'autres personnes, et je posterai mon nouveau code. A savoir que je posterai le cryptage avec césar. Et si tu pouvait m'aider pour la fonction de décryptage, je n'y arrive pas.


J'ai quelques questions:

1)

Code:


#include <stdio.h>
#include <string.h>

void fclean (char *line, FILE * fp)
{
  char *p = strchr (line, '\n');
  if (p != NULL)
  {
      *p = 0;
  }
  else
  {
      int c;
      while ((c = fgetc (fp)) != '\n' && c != EOF)
      {
      }
  }
}


Je ne comprend pas le else... tu pourrais m'expliquer?

2) Toutes les nouvelles fonctions ne devraient-elles pas être déclarées dans polybe.h ?

3)

Code:

fclean (s_phraseACrypter, stdin);

  {
      int n = crypterPolybe (s_phraseCryptee, s_phraseACrypter);
      afficherCryptee (s_phraseCryptee, n);
  }

A quoi servent les {} ? Pour quelle fonction ?

4)

Code:

static void afficherCryptee (char const *s_phraseCryptee, int n)

Je ne comprend pas ces arguments peux-tu m'expliquer ?

Au niveau de l'amélioration:
- la gestion des majuscules, il suffit de créer une boucle avec toupper() ?
- la gestion des accents: est il possible de transformer un "é" par exemple en "e" (le carré de Polybe ne gérant pas lui-même les accents)... ou de faire une gestion des exceptions ?
- gestion des espaces :les 0 sont-ils remplaçables par un espace? Car x == " " par exemple n'affiche pas un espace...

merci d'avance !

azerty
Bavard
Bavard

Messages : 15
Date d'inscription : 17/11/2008

Revenir en haut Aller en bas

Cryptage Carré de Polybe... Empty UP !

Message  azerty Sam 22 Nov 2008 - 22:28

Up, please !

azerty
Bavard
Bavard

Messages : 15
Date d'inscription : 17/11/2008

Revenir en haut Aller en bas

Cryptage Carré de Polybe... Empty Re: Cryptage Carré de Polybe...

Message  -ed- Dim 23 Nov 2008 - 17:40

azerty a écrit:
Code:

#include <stdio.h>
#include <string.h>

void fclean (char *line, FILE * fp)
{
  char *p = strchr (line, '\n');
  if (p != NULL)
  {
      *p = 0;
  }
  else
  {
      int c;
      while ((c = fgetc (fp)) != '\n' && c != EOF)
      {
      }
  }
}
Je ne comprend pas le else... tu pourrais m'expliquer?
http://mapage.noos.fr/emdel/notes.htm#saisie
http://mapage.noos.fr/emdel/notes.htm#fichiers

2) Toutes les nouvelles fonctions ne devraient-elles pas être déclarées dans polybe.h ?
Ca dépend si elles ont publiques ou non (static)...

3)
Code:

fclean (s_phraseACrypter, stdin);

  {
      int n = crypterPolybe (s_phraseCryptee, s_phraseACrypter);
      afficherCryptee (s_phraseCryptee, n);
  }

A quoi servent les {} ? Pour quelle fonction ?
en C90, une variable doit être définie au début d'un bloc. Aucun rapport avec une fonction.
[quote]
4)

Code:

static void afficherCryptee (char const *s_phraseCryptee, int n)
[/quote]
s_phraseCryptee : pointeur sur un char non modifiable. C'est l'adresse du premier élément du tableau de char qui contient la chaine cryptée.
n : entier de type int. C'est le nombre d'éléments du tableau de char qui contient la chaine cryptée.

Je ne comprend pas ces arguments peux-tu m'expliquer ?
Au niveau de l'amélioration:
- la gestion des majuscules, il suffit de créer une boucle avec toupper() ?
Par exemple, ou l'ajouter dans une boucle existante (éviter de multiplier les boucles quand une suffit).

- la gestion des accents: est il possible de transformer un "é" par exemple en "e"
Pas de manière portable, car le langage C ne connait pas 'é'. Il faut le faire à la main.

J'ai fait ça ...

http://mapage.noos.fr/emdel/clib.htm
Module ASCII (nom mal choisi, mais c'est comme ça...)
- gestion des espaces :les 0 sont-ils remplaçables par un espace?
Quels 0 ?
Car x == " " par exemple n'affiche pas un espace...
une expression ne peut pas afficher quoi que ce soit. Soit plus précis, je ne comprends pas ta demande.
-ed-
-ed-
Admin
Admin

Messages : 290
Date d'inscription : 26/05/2008
Age : 67
Localisation : Paris 14eme arrondissement (75, France)

http://bien-programmer.fr

Revenir en haut Aller en bas

Cryptage Carré de Polybe... Empty Espaces

Message  azerty Dim 23 Nov 2008 - 23:01

En gros quand l'utilisateur rentre "je programme" j'aimerai que le résultat soit "4421 3456..." (heu j'ai mis les nombres au hasard), l'espace étant présent dans le phrase codée...

azerty
Bavard
Bavard

Messages : 15
Date d'inscription : 17/11/2008

Revenir en haut Aller en bas

Cryptage Carré de Polybe... Empty Re: Cryptage Carré de Polybe...

Message  -ed- Dim 23 Nov 2008 - 23:14

azerty a écrit:En gros quand l'utilisateur rentre "je programme" j'aimerai que le résultat soit "4421 3456..." (heu j'ai mis les nombres au hasard), l'espace étant présent dans le phrase codée...
Ce que tu veux dire, en clair, c'est que la structure de la phrase doit être préservée (espaces, ponctuation, fins de ligne ?)
-ed-
-ed-
Admin
Admin

Messages : 290
Date d'inscription : 26/05/2008
Age : 67
Localisation : Paris 14eme arrondissement (75, France)

http://bien-programmer.fr

Revenir en haut Aller en bas

Cryptage Carré de Polybe... Empty codage

Message  azerty Lun 24 Nov 2008 - 16:11

Oui. au moins les espaces, la ponctuation c'est moins important (dans l'idéal il faudrait carrément supprimer la ponctuation... je pense inclure cela dans une autre fonction static, mais dois-je gérer chaque type de ponctuation à la main ?).

azerty
Bavard
Bavard

Messages : 15
Date d'inscription : 17/11/2008

Revenir en haut Aller en bas

Cryptage Carré de Polybe... Empty Re: Cryptage Carré de Polybe...

Message  -ed- Lun 24 Nov 2008 - 16:58

azerty a écrit:Oui. au moins les espaces, la ponctuation c'est moins important (dans l'idéal il faudrait carrément supprimer la ponctuation... je pense inclure cela dans une autre fonction static, mais dois-je gérer chaque type de ponctuation à la main ?).
Il faut différencier le traitement du caractère en fonction de son appartenance. Tu peux utiliser ispunct(), par exemple.
Code:

#nbclude <ctype.h>

{
  for(...)
  {
      c = tab[i];
      if (ispunct(c))
      {
        ...
      }
      else
      {
        ...
      }
il faut un critère équivalent au décodage. Dans ton cas, si j'ai bien compris, ce serait isdigit(), puis on assemblerait les chiffres 2 à 2 pour en faire une valeur numérique que l'on transformerait alors en caractère en utulisant l'algo inverse (ou le même, je ne sais pas si il est symétrique comme un ROT-13, par exemple), tout en laissant les autres caractères (ponctuation) inchangés...
-ed-
-ed-
Admin
Admin

Messages : 290
Date d'inscription : 26/05/2008
Age : 67
Localisation : Paris 14eme arrondissement (75, France)

http://bien-programmer.fr

Revenir en haut Aller en bas

Cryptage Carré de Polybe... Empty ok

Message  azerty Mer 26 Nov 2008 - 19:41

Merci !
Où puis-je trouver de la documentation en français sur ces deux fonctions ?

azerty
Bavard
Bavard

Messages : 15
Date d'inscription : 17/11/2008

Revenir en haut Aller en bas

Cryptage Carré de Polybe... Empty Re: Cryptage Carré de Polybe...

Message  -ed- Jeu 27 Nov 2008 - 2:51

azerty a écrit:Merci !
Où puis-je trouver de la documentation en français sur ces deux fonctions ?
Dans ton livre de C ?

Sinon : http://man.developpez.com/man3/ C'est orienté Linux, mais dans l'ensemble, les informations sont correctes.

Au fait, pourquoi "en français" ? Pour avancer dans ce métier, il faut savoir bien lire l'anglais.
-ed-
-ed-
Admin
Admin

Messages : 290
Date d'inscription : 26/05/2008
Age : 67
Localisation : Paris 14eme arrondissement (75, France)

http://bien-programmer.fr

Revenir en haut Aller en bas

Cryptage Carré de Polybe... Empty Francais?

Message  azerty Ven 28 Nov 2008 - 11:33

Oui... mais je met 2 fois plus de temps avec une doc en anglais, ce qui ne me dérange pas habituellement, mais vu que c'est pressé...

azerty
Bavard
Bavard

Messages : 15
Date d'inscription : 17/11/2008

Revenir en haut Aller en bas

Cryptage Carré de Polybe... Empty Re: Cryptage Carré de Polybe...

Message  Contenu sponsorisé


Contenu sponsorisé


Revenir en haut Aller en bas

Revenir en haut

- Sujets similaires

 
Permission de ce forum:
Vous ne pouvez pas répondre aux sujets dans ce forum
Ne ratez plus aucun deal !
Abonnez-vous pour recevoir par notification une sélection des meilleurs deals chaque jour.
IgnorerAutoriser