Partage
  • Partager sur Facebook
  • Partager sur Twitter

copie de chaine de carractere avec strcpy()

et allocation dynamique

Sujet résolu
    18 septembre 2019 à 1:34:44

    bonjour a tous

    j'ai besoin de faire une copie d'une chaîne de caractère, puis de la remplacer par des "*" pour masquer les caractère en question

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main()
    {
        //demande d'allocation de mémoire
        int i = 0 ;
        char motSecret[] = "MARRON";
        char mot = malloc(strlen(motSecret)+2 * sizeof(char));
        strcpy(mot, motSecret);
        //char mot[] = "MARRON";
        for ( i = 0 ; i < strlen(motSecret) ; i++)
        {
             mot[i] = "*";
        }
    
    
        printf("le mot %s ", mot);
        return 0;
    }
    



    ce code ne fonctionne pas. j'obtien le journal d'erreur suivant :

    ||=== Build: Debug in test3 (compiler: GNU GCC Compiler) ===|
    C:\Users\admin\prog\c\projets\test3\main.c||In function 'main':|
    C:\Users\admin\prog\c\projets\test3\main.c|10|warning: initialization makes integer from pointer without a cast [-Wint-conversion]|
    C:\Users\admin\prog\c\projets\test3\main.c|11|warning: passing argument 1 of 'strcpy' makes pointer from integer without a cast [-Wint-conversion]|
    C:\Program Files (x86)\CodeBlocks\MinGW\include\string.h|45|note: expected 'char *' but argument is of type 'char'|
    C:\Users\admin\prog\c\projets\test3\main.c|15|error: subscripted value is neither array nor pointer nor vector|
    C:\Users\admin\prog\c\projets\test3\main.c|19|warning: format '%s' expects argument of type 'char *', but argument 2 has type 'int' [-Wformat=]|
    ||=== Build failed: 1 error(s), 3 warning(s) (0 minute(s), 0 second(s)) ===|
    

    si je commente les lignes 10 et 11, et dé commente la ligne 12, mon problème disparaît.

    pourquoi la copie de ma chaîne ne veut pas fonctionner de la même manière qu'une chaîne créé simplement?

    une autre tout petit problème, ma ligne 15 ne remplace pas les caractère par des * mais par des $, je comprend pas bien pourquoi ^^ mais c'est pas très grave

    Edit: petit précision : j'ai ajouté 2 à sizeof(char) afin d'être sûr que la chaîne a serai assez longue... Sachant qu'un char fait 1octet et que le strlen(motSecret) devrais je pense avoir compté le \0 de fin de chaîne 

    -
    Edité par cobra7476 18 septembre 2019 à 1:47:49

    • Partager sur Facebook
    • Partager sur Twitter
      18 septembre 2019 à 8:01:41

      Salut,

      La variable mot devrait être déclarée comme pointeur: char *mot = malloc...

      En ligne 15 ce devrait être: mot[i] = '*';

      -
      Edité par magma 18 septembre 2019 à 8:04:09

      • Partager sur Facebook
      • Partager sur Twitter
        18 septembre 2019 à 8:28:38

        et mince... un souci de rigoureusité... merci

        mais alors..

        à quel moment ma variable mot contien un pointeur? et a quel moment est-ce que sa devien un tableau comme MotSecret?

        dit moi où est-ce que je me trompe?

        #include <stdio.h>
        #include <stdlib.h>
        #include <string.h>
        
        int main()
        {
            //demande d'allocation de mémoire
            int i = 0 ;
            char motSecret[] = "MARRON";
            char *mot = malloc(strlen(motSecret) * sizeof(char));
            strcpy(mot, motSecret);
            //char mot[] = "MARRON";
            for ( i = 0 ; i < strlen(motSecret) ; i++)
            {
                 mot[i] = '*';
            }
        
        
            printf("le mot %s ", mot);
            return 0;
        }

        ligne 10, mot est un pointeur?

        ligne 11, strcpy demande un char... mais je lui donne un pointeur sur un tableau de char et j'ai aucune erreur ?

        ligne 15 et 19 : je me sert de mot comme d'un tableau de char et j'ai toujours aucun souci ?



        -
        Edité par cobra7476 18 septembre 2019 à 8:38:52

        • Partager sur Facebook
        • Partager sur Twitter
          18 septembre 2019 à 9:55:43

          Ligne 10, mot est déclaré comme pointeur sur char, il est initialisé avec l'adresse d'un bloc mémoire de la taille de 6 caractères (char). 

          Ligne 11, strcpy ne demande pas un char mais deux pointeurs sur char, les paramètres sont donc correctes.

          Il y a un tout de même un petit problème, c'est que le tableau motsecret  à une taille de 7 char et tu le copie dans un tableau de 6 char. (il ne faut pas oublier que les chaîne de caractères se terminent par le caractère '\0'.

          • Partager sur Facebook
          • Partager sur Twitter
            18 septembre 2019 à 10:07:20

            Mais... 

            OK donc strlen() ne compte pas le /0

            Mais ligne 10, tu dit que les deux paramètres sont correct ?

            1er argument, mot est bien un pointeur, ok

            Mais le 2 eme arguments, motSecret, c'est pas un pointeur c'est un tableau de char non ? 

            • Partager sur Facebook
            • Partager sur Twitter
              18 septembre 2019 à 10:21:26

              cobra7476 a écrit:

              Mais le 2 eme arguments, motSecret, c'est pas un pointeur c'est un tableau de char non ? 

               _____

              motSecret est équivalent à &motSecret[0]

              (L'adresse du 1er élément du tableau motSecret)



              • Partager sur Facebook
              • Partager sur Twitter
                18 septembre 2019 à 10:35:51

                Effectivement strlen ne compte pas le '\0'.

                En fait les tableaux sont passé par adresse aux fonctions, ce qui veut dire que l'on envoi l'adresse du premier élément du tableau à la fonction.

                • Partager sur Facebook
                • Partager sur Twitter
                  18 septembre 2019 à 11:56:28

                  par souci de rigourosité,

                  • sizeof(char) est par définition égal à 1.
                  • pour faire une copie d'une chaine de caractères, il faut allouer    strlen(str)+1 octets. Pas +2.
                  • la fonction strdup existe. Extension GNU depuis des siècles,  POSIX depuis 2008 et maintenant standard C ?
                  • c'est une très mauvaise idée de faire un appel à  strlen dans le test d'un for

                  > motSecret est équivalent à &motSecret[0]

                  Pas dans tous les contextes

                  #include <stdio.h>
                  
                  int main()
                  {
                      char m[] = "MARRON";
                  	printf("%zu\n", sizeof(m    ));
                  	printf("%zu\n", sizeof(&m[0]));
                  }
                  

                  Exécution

                  $ gcc sz.c -Wall
                  $ ./a.out 
                  7
                  8
                  


                  C'est pour ça qu'on dit que le nom d'un tableau se dégrade (decays) en adresse (de son premier élément) lors d'une évaluation. Mais sizeof () est un opérateur du langage, qui n'évalue pas son argument.

                  -
                  Edité par michelbillaud 18 septembre 2019 à 12:09:10

                  • Partager sur Facebook
                  • Partager sur Twitter
                    18 septembre 2019 à 14:53:03

                    Décidément... J'ai pas encore tout compris avecavec les pointeurs moi..

                     Pour moi

                    -motSecret ou motSecret[0] contient MARRON

                    -&motSecret, ou &motSecret[0] contient L'ADRESSE memoire où démarre le contenu de motSecret[0] ou motSecret

                    Pour moi ce n'est donc pas équivalent.. =o

                    À l'inverse, quand

                    Char* mot;

                     mot contient l'adresse mémoire et *mot contiendra MARRON c'est ça ? 

                    -
                    Edité par cobra7476 18 septembre 2019 à 14:58:52

                    • Partager sur Facebook
                    • Partager sur Twitter
                      18 septembre 2019 à 15:12:29

                      motSecret c'est lui le tableau : il contient les caractères 'M', 'A', 'R', 'R', 'O', 'N' et '\0'. Mais toute utilisation le verra comme un pointeur sur le premier des caractères donc pointe sur le caractère 'M'.
                      motSecret[0] contient le caractère 'M'.
                      &motSecret est l'adresse d'un tableau, c'est donc l'adresse de 'M' 'A' 'R' 'R' 'O' 'N' '\0'.
                      &motSecret[0] est l'adresse du caractère 'M'.

                      Donc les valeurs motSecret et &motSecret et &motSecret[0] sont bien égales (mais elles n'ont pas le même type la première et la dernières sont des char*, la seconde est un char (*)[7].)

                      mot contient une adresse mémoire : oui. Mais pour le moment cette adresse est totalement aléatoire (pointe donc n'importe où).
                      *mot contient UN UNIQUE caractère celui qui est désigné par le pointeur mot. A ne surtout pas utiliser tant que mot n'a pas été initialisé correctement.

                      • Partager sur Facebook
                      • Partager sur Twitter

                      En recherche d'emploi.

                        18 septembre 2019 à 15:14:03

                        motSecret[0] contient première lettre de MARRON.

                        &motSecret renvoi l'adresse du tableau

                        &motSecret[0] renvoi l'adresse de la première case du tableau, c'est la même, c'est de type qui est différent.

                        motSecret renvoi aussi l'adresse de la première case du tableau. (sauf s'il est utilisé avec sizeof)

                        char* mot; déclare un pointeur sur char non initialisé.

                        mot contient l'adresse mémoire sur l'objet sur lequel il pointe, s'il est initialisé bien sûr.

                        *mot donne accès à l'élément pointé.

                        Effectivement il va falloir reprendre ton cours, parce que ça part dans tout les sens.

                        • Partager sur Facebook
                        • Partager sur Twitter
                          18 septembre 2019 à 16:09:34

                          Bon. Merci bien à tous, ça me paraît clair là façon dont vous me l'expliquez, je m'y perdai à l'utilisation. On verra à l'avenir je vais faire mes tests sa m'aidera a comprendre et à retenir, merci bien 

                          • Partager sur Facebook
                          • Partager sur Twitter
                            18 septembre 2019 à 16:17:54

                            Normal d'avoir du mal à comprendre : l'idée - lors de la conception de C - était tordue : au départ, un simple pointeur sur une zone contenant les éléments (héritage de B, je crois). Puis une constante représentant l'adresse de cette zone.

                            Voir embryonic C, dans https://web.archive.org/web/20150611114355/https://www.bell-labs.com/usr/dmr/www/chist.html

                            Le problème, c'est que la plupart des programmeurs n''ont connu que cette vision des tableaux, et croient que c'est la seule et vraie façon de voir.

                            -
                            Edité par michelbillaud 18 septembre 2019 à 16:19:17

                            • Partager sur Facebook
                            • Partager sur Twitter
                              18 septembre 2019 à 18:48:34

                              michelbillaud a écrit:

                              Voir embryonic C, dans https://web.archive.org/web/20150611114355/https://www.bell-labs.com/usr/dmr/www/chist.html

                              je ne suis malheureusement pas assez à l'aise avec l'anglais pour tout comprendre. mais je vois en tout cas que cette histoire ne date pas d'hier ^^ mais là sont les racines, et elles restent apparemment fortement encré dans le langage, mais t’inquiète, je vais tout comprendre et m'y faire

                              ce que je trouve tout de même compliqué, moi qui vien de la programmation web (principalement PHP, autodidacte mais ya déja quelques année) c'est que cette fois, c'est pas très facile de demander a php de quel type est tel variable, que contient-t-elle ? une lettre ou une chaîne? de type nombre ou bien une chaîne de caractère? bon, ya aussi la notion que tout est nombre... avec ASCII, je sais, mais voilà

                              bref, c'est très différent, néanmoins je retrouve pas mal de choses et c'est enrichissant :) plus bas niveau donc on comprend des concept informatique, notamment cette table ASCII que je ne connaissais pas du coté programmation. et puis ces histoire d'adresse mémoire.. j'imagine qu'il y en aura peut être d'autres

                              ton lien je le garde de coté et me penche dessus quand même à essayer de comprendre, sa me semble très intéressant ^^ des accident de syntaxe qui ont aboutie a des complexifications du langage j'ai vu par exemple... LOL

                              • Partager sur Facebook
                              • Partager sur Twitter
                                18 septembre 2019 à 20:27:20

                                Personnellement je trouve que, surtout si on n'est pas super à l'aise avec les pointeurs, mieux vaut définir des chaînes de caractères de longueur fixe (*). Il y a plein de situation où les chaînes de caractères ont naturellement une longueur maximale. Pour le jeu du pendu, par exemple, on peut se limiter à 26 caractères (taille 27 avec le zéro terminal) puisque le mot le plus long, « intergouvernementalisation », en fait 26. Si c'est pour mémoriser des noms de joueurs dont on affichera le score, il suffit de spécifier une taille limite (tout le monde fait ça, non ?).

                                -----

                                (*) Je parle de la définition, pas de la déclaration d'un paramètre de fonction.

                                • Partager sur Facebook
                                • Partager sur Twitter
                                  18 septembre 2019 à 22:44:09

                                  robun a écrit:

                                  Pour le jeu du pendu, par exemple, on peut se limiter à 26 caractères (taille 27 avec le zéro terminal) puisque le mot le plus long, « intergouvernementalisation », en fait 26.

                                  _____

                                  C'est sans compter le chlorure d’aminométhylpyrimidinylhydroxyéthylméthythiazolium (49 lettres).



                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    18 septembre 2019 à 23:17:04

                                    mon objectif personnellement, c'est quand même de comprendre les pointeur :) ce serai dommage de coder en C et de chercher a contourner une fonctionnalité du langage, et je pense avoir plutôt bien compris on verra si j'ai d'autres souci comme celui ci je reviendrai d'abord lire l'aide que j'ai eu ici, je pense pouvoir résoudre mes souci de pointeur seul à présent
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      18 septembre 2019 à 23:47:29

                                      michelbillaud a écrit:

                                      C'est pour ça qu'on dit que le nom d'un tableau se dégrade (decays) en adresse (de son premier élément) lors d'une évaluation. Mais sizeof () est un opérateur du langage, qui n'évalue pas son argument.

                                      L'opérateur sizeof n'évalue pas son opérande, sauf exception bien sûr. ;-)
                                      C11 6.5.3.4§1 The sizeof operator yields the size (in bytes) of its operand [...] The result is an integer. If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant.
                                      C11 6.7.6.2§5 : Where a size expression is part of the operand of a sizeof operator and changing the value of the size expression would not affect the result of the operator, it is unspecified whether or not the size expression is evaluated.

                                      A part ça, il existe un cas simple où l'identificateur d'un tableau ne se comporte pas du tout comme celui d'un pointeur.

                                      char t[6] = "hello";
                                      char *p;
                                      char q[6];
                                      p = t;  // OK
                                      q = t:  // pas OK

                                      C'est le and is not an lvalue de la règle complète de la norme qui fait ici la différence:
                                      C11 6.3.2.1§3 Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.

                                      -
                                      Edité par Marc Mongenet 18 septembre 2019 à 23:53:41

                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        19 septembre 2019 à 7:02:07

                                        Pour le second point, c'est pour le cas sizeof (t[ f(i) ] ) ?

                                        EDIT:

                                        Dans le draft C18, https://web.archive.org/web/20181230041359if_/http://www.open-std.org/jtc1/sc22/wg14/www/abq/c17_updated_proposed_fdis.pdf

                                        << 6.5.3.4. note 2

                                        The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer. If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant
                                        >>

                                        Je suppose que "évaluer un VLA", dans le sens du standard, se limite à regarder son type et sa taille, qui est dynamique ?

                                        - Pour l'utilisation des pointeurs : on n'en est plus à l'époque où on écrivait du code C de telle ou telle façon en sachant ce que le compilateur en ferait.  On peut manipuler un tableau avec des indices, et si on regarde le code généré, constater qu'il a transformé ça en manipulation de registres travaillant sur des adresses. Et que ça donne exactement le même code avec des pointeurs Donc privilégier la simplicité d'écriture.   Si on veut se la péter optimisation, commencer par compiler avec les bonnes options :-)

                                        -
                                        Edité par michelbillaud 19 septembre 2019 à 9:31:58

                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          20 septembre 2019 à 1:34:04

                                          Pour C11/C18 6.7.6.2§5 je pense que dans

                                          int f(int x) {
                                                  sizeof(int(*)[x++]);
                                                  return x;
                                          }
                                          

                                          l'éventuelle évalutation de x++ n'est pas spécifiée (cela dit, gcc et clang n'évaluent pas).

                                          En outre, ça me semble contradictoire avec C11 6.5.3.4§1/C18 6.5.3.4§2 qui ne laisse pas de place à un comportement non spécifié.

                                          • Partager sur Facebook
                                          • Partager sur Twitter

                                          copie de chaine de carractere avec strcpy()

                                          × 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