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 :

Pointeur, strcpy et insertion d'un caractère indésirable


Sujet :

C

  1. #1
    Futur Membre du Club
    Homme Profil pro
    bibliothécaire
    Inscrit en
    Mars 2017
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : bibliothécaire

    Informations forums :
    Inscription : Mars 2017
    Messages : 9
    Points : 9
    Points
    9
    Par défaut Pointeur, strcpy et insertion d'un caractère indésirable
    Bonjour,

    Dans un cadre pédagogique, j'ai écrit un petit programme qui transforme les chiffres arabes (1, 2, 3...) présents dans un texte en chiffres écrits en lettres (un, deux, trois...).
    Ce petit programme fonctionne correctement.

    En cours de réalisation, j'ai testé de nombreuses possibilités.
    J'ai finalement réussi à faire fonctionner mon petit programme en utilisant "memset (etape1, 0, 2047);" en ligne 82 plutôt que "strcpy(etape1, "");" en ligne 81.

    Toujours dans un but pédagogique, j'aimerais comprendre pourquoi "strcpy(etape1, "");", en ligne 81, ne fonctionne pas.

    Si "strcpy(etape1, "");" en ligne 81 ne fonctionnait jamais, je ne me poserais pas de questions mais "strcpy(etape1, "");" provoque un comportement fautif (ajout d'un caractère aléatoire devant le chiffre arabe transformés en lettres) uniquement quand le plus élevé des chiffres arabes traités est précédé de 2, 4, 5 ou 6 caractères.
    Dans tous les autres cas, "strcpy(etape1, "");" en ligne 81 fonctionne aussi bien que "memset (etape1, 0, 2047);" en ligne 82.

    Donc :
    - Le 1er chiffre arabe traité (transformé en lettre) est toujours le plus élevé.
    - Avec "strcpy(etape1, "");", en ligne 81, il y a ajout d'un caractère indésirable quand et uniquement quand, ce 1er chiffre est précédé de 2, 4, 5 ou 6 caractères.
    - Si il y a plusieurs chiffres arabes à traiter, seul le 1er est affecté.
    - "strcpy(etape1, "");" fonctionne quand le 1er chiffre traité est précédé de 0, 1, 3, 7 et plus caractères.
    - Est-ce que quelqu'un peut m'expliquer le comportement fautif de "strcpy(etape1, "");" ?


    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
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    static void purger(char *chaine)  //On cherche le caractère \n (touche entrée) et on le supprime.
    {
      char *p = strchr(chaine, '\n');
      if (p)
      {
          *p = 0;
      }
      }
     
     
      int main()
     {
        char *entrante, *apres, *motcherche, *motremplace, *etape1, *etape2, *original;
     
        // Changer la valeur du <# si on ajoute des éléments au tableau.
      char *motcherchetemp [] = {
      "50","49","48","47","46","45","44","43","42","41",
      "40","39","38","37","36","35","34","33","32","31",
      "30","29","28","27","26","25","24","23","22","21",
      "20","19","18","17","16","15","14","13","12","11",
      "10","9","8","7","6","5","4","3","2","1","0","otcobre"};
     
     char *motremplacetemp [] = {
           "cinquante","quarante-neuf","quarante-huit","quarante-sept","quarante-six","quarante-cinq","quarante-quatre","quarante-trois","quarante-deux","quarante-et-un",
           "quarante","trente-neuf","trente-huit","trente-sept","trente-six","trente-cinq","trente-quatre","trente-trois","trente-deux","trente-et-un",
            "trente","vingt-neuf","vingt-huit","vingt-sept","vingt-six","vingt-cinq","vingt-quatre","vingt-trois","vingt-deux","vingt-et-un",
           "vingt","dix-neuf","dix-huit","dix-sept","seize","quinze","quatorze","treize","douze","onze",
           "dix","neuf","huit","sept","six","cinq","quatre","trois","deux","un","zero","octobre"};
     
        entrante = (char *)malloc(sizeof(char)*2048);
        original = (char *)malloc(sizeof(char)*2048);
        apres = (char *)malloc(sizeof(char)*2048);
        motcherche = (char *)malloc(sizeof(char)*1024);
        motremplace = (char *)malloc(sizeof(char)*1024);
        etape1 = (char *)malloc(sizeof(char)*2048);
        etape2 = (char *)malloc(sizeof(char)*2048);
     
        size_t LongApres, LongTotal, LongAvant, Pos;
        int LongMotCherche;
        //char espace [] = " ";
        int compteur = 1;
        int x = 0;
        int condi1 = 1;
     
        if (entrante == NULL || apres == NULL || motcherche == NULL || motremplace == NULL || etape1 == NULL  || etape2 == NULL)
        {
            puts ("Allocation impossible ! Banzai !");
            exit(1);
        }
     
        puts("Saisissez quelque chose d'un peu long.\nLe programme remplacera les chiffres arabes par des chiffres en lettres :");
        puts("\n");
        fgets(entrante, 2047, stdin);
        purger(entrante);
        strcpy(original, entrante);
     
     // Début du  code pour changer les chiffres arabes en chiffres en lettres.
     
     while (condi1 == 1 &&  x<52) // La valeur a laquelle est comparée x doit être égale au nombre d'éléments des tableaux.
     {
     
     motcherche = *(motcherchetemp+x);
     apres = strstr(entrante, motcherche);
     
     if (apres != NULL)
     {
     
     LongMotCherche = strlen(motcherche);
     LongApres = strlen(apres);
     LongTotal = strlen(entrante);
     LongAvant = LongTotal - LongApres;
     Pos = LongAvant+1;
     puts("\n");
     printf("Passage no - %d", compteur);
     puts("\n");
     strcpy(etape1, "");  //Pourquoi cela ne fonctionne pas avec strcpy quand LongAvant = 2 4 5 ou 6.
     //memset (etape1, 0, 2047); //Avec cette ligne memset, cela fonctionne très bien dans tous les cas.
     printf("Texte dans la variable 'etape1' avant memcpy :\n\"%s\"\n", etape1);
     puts("\n");
     memcpy(etape1, entrante, LongAvant);
     printf("Texte dans la variable 'etape1' apres memcpy :\n\"%s\"\n", etape1);
     puts("\n");
     
     
        puts("\n");
        printf("Texte original :\n\"%s\"\n", entrante);
        puts("\n");
        printf("La taille du motcherche ( %s ) est = %d.", motcherche, sizeof(motcherche));
        puts("\n");
        printf("Longueur du mot cherche stocke dans la variable 'LongMotChr' : %d", LongMotCherche);
        puts("\n");
        printf("Texte dans la variable apres :\n\"%s\"\n", apres);
        puts("\n");
        printf("Texte dans la variable apres+2 :\n\"%s\"\n", apres+2);
        puts("\n");
        printf("Longueur du texte stocke dans la variable 'LongTotal' :\n\"%d\"\n", LongTotal);
        puts("\n");
        printf("Longueur du texte stocke dans la variable 'apres' :\n\"%d\"\n", LongApres);
        puts("\n");
        printf("Longueur du texte stocke dans la variable 'LongAvant' :\n\"%d\"\n", LongAvant);
        puts("\n");
        printf("Position du debut de la chaine recherche stocke dans la variable 'Pos' :\n\"%d\"\n", Pos);
        puts("\n");
        printf("Texte dans la variable 'etape1' avant les ajouts :\n\"%s\"\n", etape1);
        puts("\n");
     
        motremplace = motcherche;
        motremplace = *(motremplacetemp+x);
     
        strcat (etape1, motremplace);
        printf("Texte dans la variable 'etape1' apres les ajouts :\n\"%s\"\n", etape1);
        puts("\n");
        memset (etape2, 0, 2047);
        strcpy(etape2, apres+LongMotCherche);
        printf("Texte dans la variable (etape2 = apres+3) :\n\"%s\"\n", etape2);
        puts("\n");
        strcat (etape1, etape2);
        printf("Resultat final obtenu par 'strcat(etape1, etape2)':\n\"%s\"\n", etape1);
        puts("\n");
        printf("Valeur de motcherche a la fin du processus:\n\"%s\"\n", motcherche);
        memset (entrante, 0, 2047);
        strcpy(entrante, etape1);
        memset (etape1, 0, 2047);
        puts("\n");
        //getchar();
        printf("Valeur de entrante apres 'strcpy(entrante, etape1)' = \"%s\"\n", entrante);
        puts("\n");
        compteur++;
     
        condi1 = 1;
        }
        else
        {
        x++;
        }
     
    }
        puts("\n");
        printf("Texte original : \"%s\"", original);
        puts("\n");
        puts("\n");
        printf("Resultat apres conversion des chiffres en lettres : \"%s\"", entrante);
        puts("\n");
         return *entrante;
    }
    Merci d'avance aux plus malins que moi.

  2. #2
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    (Au passage, si tu as besoin de tous ces casts de malloc(), c'est que tu compiles en C++. Retire-les. De plus, pourquoi ne pas faire toutes ces allocations dès la déclaration de ces variables?)
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    Expert confirmé
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Points : 4 182
    Points
    4 182
    Par défaut
    Tu n'initialises pas le buffer passé en premier paramètre de strcpy. Ce dernier ne contient donc probablement pas une chaîne valide, ou pas celle à laquelle tu penses (la chaîne vide). Ça « fonctionne » avec le memset car remplir le buffer avec des zéros construit incidemment la chaîne vide par la même occasion. Relis la section du cours C sur les chaînes de caractères et le man de strcpy.

    Il y a bien d'autres choses surprenantes au sein de ce morceau de code, mais allons-y étape par étape.

  4. #4
    Futur Membre du Club
    Homme Profil pro
    bibliothécaire
    Inscrit en
    Mars 2017
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : bibliothécaire

    Informations forums :
    Inscription : Mars 2017
    Messages : 9
    Points : 9
    Points
    9
    Par défaut Merci.
    Médinoc et Matt, merci pour vos commentaires.

    Je suis un complet néophyte en matière de programmation.
    J’utilise des livres, des cours sur Internet et Google pour apprendre et expérimenter.
    Voilà pourquoi mon code n’est sûrement pas parfait aux yeux des programmeurs plus aguerris. De là tous ces mallocs() et choses surprenantes. De nombreuses lignes sont là uniquement pour me permettre de comprendre ce qui se passe lors de l’exécution.
    Je rédige de mon mieux de petits programmes qui font de petites choses et j’essaie de comprendre durant le processus.

    Ceci dit, je comprends bien que le buffer passé en premier paramètre de strcpy en ligne 81 n’est pas initialisé et ne contient probablement pas de chaînes valides.

    Ce que je ne comprends pas, c’est :

    Pourquoi cela fonctionne toujours quand le 1er chiffre traité est précédé de 0, 1, 3 et 7 caractères ou plus.

    Pourquoi cela ne fonctionne jamais quand le 1er chiffre traité est précédé de 2, 4, 5 ou 6 caractères.

    À chaque exécution du programme le contenu du buffer devrait varié et il devrait toujours y avoir un caractère étrange qui précède le chiffre écrit en lettre ou, du moins, le programme, avec strcpy, devrait parfois fonctionner, parfois ne pas fonctionner, peu importe le nombre de caractères qui précède le premier chiffre traité.

    Même avec strcpy et un buffer non-initialisé les chiffres contenus dans les phrases suivantes seront toujours correctement converti en lettre :
    18 19
    7........8
    7.......8
    7......8
    1
    1....
    12 11 10
    29 30
    ---30
    ab 30
    -30
    -1
    ...3
    aime- 1 chat

    Alors que le premier chiffres le plus élevé contenu dans les phrases suivantes ne sera jamais correctement converti en lettre :
    1 2
    1 2 3
    18 19 20
    19 18 20
    38 39 40
    1 2 3 4
    7.....8
    9 10
    9 10 11
    10 11 12
    ......12 11
    -----12
    1 29 30
    1 19
    --30
    aime 1 chat
    aime 12 chats.
    aime- 1 chat


    Anyways… Merci pour vos remarques, je vais poursuivre mes lectures.

  5. #5
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Points : 11 877
    Points
    11 877
    Par défaut
    Résultat indéterminé dû à un souci quelque part comme l'ont dit d'autres. Par exemple:

    Saisissez quelque chose d'un peu long.
    Le programme remplacera les chiffres arabes par des chiffres en lettres :


    18 19 20


    Passage no - 1

    Texte dans la variable 'etape1' avant memcpy :
    ""


    Texte dans la variable 'etape1' apres memcpy :
    "18 19 "




    Texte original :
    "18 19 20"


    La taille du motcherche ( 20 ) est = 8.

    Longueur du mot cherche stocke dans la variable 'LongMotChr' : 2

    Texte dans la variable apres :
    "20"


    Texte dans la variable apres+2 :
    ""


    Longueur du texte stocke dans la variable 'LongTotal' :
    "8"


    Longueur du texte stocke dans la variable 'apres' :
    "2"


    Longueur du texte stocke dans la variable 'LongAvant' :
    "6"


    Position du debut de la chaine recherche stocke dans la variable 'Pos' :
    "7"


    Texte dans la variable 'etape1' avant les ajouts :
    "18 19 "


    Texte dans la variable 'etape1' apres les ajouts :
    "18 19 vingt"


    Texte dans la variable (etape2 = apres+3) :
    ""


    Resultat final obtenu par 'strcat(etape1, etape2)':
    "18 19 vingt"


    Valeur de motcherche a la fin du processus:
    "20"


    Valeur de entrante apres 'strcpy(entrante, etape1)' = "18 19 vingt"




    Passage no - 2

    Texte dans la variable 'etape1' avant memcpy :
    ""


    Texte dans la variable 'etape1' apres memcpy :
    "18 "




    Texte original :
    "18 19 vingt"


    La taille du motcherche ( 19 ) est = 8.

    Longueur du mot cherche stocke dans la variable 'LongMotChr' : 2

    Texte dans la variable apres :
    "19 vingt"


    Texte dans la variable apres+2 :
    " vingt"


    Longueur du texte stocke dans la variable 'LongTotal' :
    "11"


    Longueur du texte stocke dans la variable 'apres' :
    "8"


    Longueur du texte stocke dans la variable 'LongAvant' :
    "3"


    Position du debut de la chaine recherche stocke dans la variable 'Pos' :
    "4"


    Texte dans la variable 'etape1' avant les ajouts :
    "18 "


    Texte dans la variable 'etape1' apres les ajouts :
    "18 dix-neuf"


    Texte dans la variable (etape2 = apres+3) :
    " vingt"


    Resultat final obtenu par 'strcat(etape1, etape2)':
    "18 dix-neuf vingt"


    Valeur de motcherche a la fin du processus:
    "19"


    Valeur de entrante apres 'strcpy(entrante, etape1)' = "18 dix-neuf vingt"




    Passage no - 3

    Texte dans la variable 'etape1' avant memcpy :
    ""


    Texte dans la variable 'etape1' apres memcpy :
    ""




    Texte original :
    "18 dix-neuf vingt"


    La taille du motcherche ( 18 ) est = 8.

    Longueur du mot cherche stocke dans la variable 'LongMotChr' : 2

    Texte dans la variable apres :
    "18 dix-neuf vingt"


    Texte dans la variable apres+2 :
    " dix-neuf vingt"


    Longueur du texte stocke dans la variable 'LongTotal' :
    "17"


    Longueur du texte stocke dans la variable 'apres' :
    "17"


    Longueur du texte stocke dans la variable 'LongAvant' :
    "0"


    Position du debut de la chaine recherche stocke dans la variable 'Pos' :
    "1"


    Texte dans la variable 'etape1' avant les ajouts :
    ""


    Texte dans la variable 'etape1' apres les ajouts :
    "dix-huit"


    Texte dans la variable (etape2 = apres+3) :
    " dix-neuf vingt"


    Resultat final obtenu par 'strcat(etape1, etape2)':
    "dix-huit dix-neuf vingt"


    Valeur de motcherche a la fin du processus:
    "18"


    Valeur de entrante apres 'strcpy(entrante, etape1)' = "dix-huit dix-neuf vingt"
    Ceci semble fonctionner pour moi ;-)

    En fait ton vrai souci vient d'exactement ce que tu as remarqué:

    - Si tu fais un memset, aucun souci
    - Si tu ne le fais pas, ta chaîne de caractère contient n'importe quoi et donc quand tu fais:
    - strcpy(etape1, ""), tu ne mets que le premier caractère à '\0' mais le reste de la mémoire est non-initialisée
    - Quand tu fais ton memcpy(etape1, entrante, LongAvant), tu ne copies que des caractères du début mais il te manque un '\0' à la fin
    - Donc quand tu fais ensuite ton strcat (etape1, motremplace);, tu n'as pas forcément de '\0' au bon endroit et donc tu va avoir n'importe quoi avant le début...

    On appelle cela un comportement indéterminé ;-)

    Pour le prouver, j'ai ajouter ceci dans ton code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
     memcpy(etape1, entrante, LongAvant);
      // Provocation de l'erreur
     etape1[LongAvant] = 'K';
     etape1[LongAvant + 1] = 'O';
     etape1[LongAvant + 2] = '\0';
    et cela me donne:
    Resultat apres conversion des chiffres en lettres : "aime KOun chat"
    Pour finir, ce n'est pas vrai que:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     strcpy(etape1, "");  //Pourquoi cela ne fonctionne pas avec strcpy quand LongAvant = 2 4 5 ou 6.
    Apprend à ne jamais utiliser le terme "cela ne fonctionne pas". "Fonctionne pas" est trop générique. Il vaut mieux dire : Que voulais-tu que cela fasse? Qu'est-ce que cela fait? Pourquoi cela ne le fait pas?

    Espérant que cela aide,
    Jc

  6. #6
    Futur Membre du Club
    Homme Profil pro
    bibliothécaire
    Inscrit en
    Mars 2017
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : bibliothécaire

    Informations forums :
    Inscription : Mars 2017
    Messages : 9
    Points : 9
    Points
    9
    Par défaut
    Merci beaucoup Fearyourself pour ta réponse très utile, pertinente et instructive pour moi.
    Je comprends mieux maintenant et c'est apprécié.

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

Discussions similaires

  1. Liste des caractères indésirables
    Par gloglo dans le forum Oracle
    Réponses: 6
    Dernier message: 19/10/2006, 18h03
  2. [Tableaux] comment virer des caractère indésirables?
    Par julien.63 dans le forum Langage
    Réponses: 3
    Dernier message: 20/07/2006, 21h25
  3. Caractère indésirable sur Excel
    Par greenweed dans le forum Macros et VBA Excel
    Réponses: 7
    Dernier message: 12/12/2005, 08h29
  4. Réponses: 8
    Dernier message: 22/06/2005, 10h34
  5. Réponses: 2
    Dernier message: 11/05/2005, 11h11

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