Partage
  • Partager sur Facebook
  • Partager sur Twitter

Le saviez-vous... ??

les "littérales chaines"

    19 juillet 2007 à 20:57:27

    Bonsoir,

    ce post tient plus de l'information que d'un problème. En effet, en lisant le livre de Bjarne Stroustrup sur le c++, j'ai appris a ma grande surprise page 101 que ce code n'est pas valide :

    char* s="Bonjour";
    s[3]='N';


    "Bonjour" est un pointeur (ça c'est normal), mais le truc moins évident (mais évident après coup) c'est que le tableau pointé par s est constant (et statique qui plus est) donc on a aps le droit de le modifier.

    En C j'ai souvent utilisé ce genre d'instructions, mais c'est invalide !

    Si vous avez des commentaires :)

    EDIT: Pour les débutants, je post le code valide quand même ;)
    char s[8]="Bonjour";
    s[3]='N';

    (Ici "Bonjour n'est plus un pointeur mais le synonyme de {'B','o','n','j','o','u','r','\0'})

    RE-EDIT: Le code tout en haut ne marche pas non plus en C (c'est vraiment bizarre que je n'ai jamais fait attention à ça !) : erreur de segmentation
    • Partager sur Facebook
    • Partager sur Twitter
    Anonyme
      20 juillet 2007 à 0:13:07

      Bonsoir.

      J'ai une question moi par contre :euh: .

      Si on met justement char* s = "blabla", ne demande-t-on pas que l'adresse de "s" soit égale à "blabla"?

      Merci
      • Partager sur Facebook
      • Partager sur Twitter
        20 juillet 2007 à 0:31:53

        on demande que l'adresse de s soit égale à la premiere adresse d'une suite d'espace mémoire contigüe de taille char. la suite de longueur inconnue se termine par '\0'.

        "blabla" est une constante littérale (un const char[])
        • Partager sur Facebook
        • Partager sur Twitter
          20 juillet 2007 à 8:50:51

          Les deux déclarations font normalement exactement la même chose

          La seule difference qu'il pourait y avoir c'est quand tu met un chiffre plus grand que 8, plus de mémoire sera reservée par ton programme et tu pourra dépasser la chaine de quelques chars sans crainte (pour lire et pour ecrire)
          Alors que pour le cas sois disant invalide, ça ne reservera que ce qu'il faut, donc si tu dépasse, il y'a une chance que tu atteigne la mémoire d'un autre programme et la , bonjour le plantage.

          Mais je ne comprend pas que ça ne marche pas chez toi, c'est quoi ton compilateur ?
          Je vais essayer voir si je dis pas de conneries tiens :-°
          • Partager sur Facebook
          • Partager sur Twitter
            20 juillet 2007 à 9:00:30

            Je parle pour le C, mais cela devrait être valable en C++.

            Citation : 3D-lite.

            Les deux déclarations font normalement exactement la même chose


            Comme l'auteur le dit lui-même, les deux déclarations n'ont pas le même effet. Déjà, déclarer un pointeur ou un tableau n'est pas la même chose en général (excepté comme paramètres d'une fonction par exemple). Ensuite, "n'importe quoi" est une chaîne littérale, un objet de type (char []), dont seul l'accès en lecture est possible. L'exception à l'usage des chaînes littérales est l'initialisation de tableaux de caractères, soit la seconde forme employée par l'auteur du topic.

            Citation

            si tu dépasse, il y'a une chance que tu atteigne la mémoire d'un autre programme et la , bonjour le plantage.


            Le DOS est mort depuis longtemps.
            • Partager sur Facebook
            • Partager sur Twitter
              20 juillet 2007 à 9:09:07

              Citation : rz0

              Comme l'auteur le dit lui-même, les deux déclarations n'ont pas le même effet. Déjà, déclarer un pointeur ou un tableau n'est pas la même chose en général (excepté comme paramètres d'une fonction par exemple). Ensuite, "n'importe quoi" est une chaîne littérale, un objet de type (char []), dont seul l'accès en lecture est possible. L'exception à l'usage des chaînes littérales est l'initialisation de tableaux de caractères, soit la seconde forme employée par l'auteur du topic.


              Jusqu'a present, pour moi, un "objet char[]" n'etait qu'un pointeur vers de la mémoire allouée normalement, aprés je peux me tromper, peut etre que le compilateur ajoute une "protection" selon les cas.

              Citation


              Citation

              si tu dépasse, il y'a une chance que tu atteigne la mémoire d'un autre programme et la , bonjour le plantage.


              Le DOS est mort depuis longtemps.


              Je parlais d'un plantage du programme, pas de l'OS heing ^^
              • Partager sur Facebook
              • Partager sur Twitter
                20 juillet 2007 à 9:29:23

                Citation : 3D-lite.

                Jusqu'a present, pour moi, un "objet char[]" n'etait qu'un pointeur vers de la mémoire allouée normalement, aprés je peux me tromper, peut etre que le compilateur ajoute une "protection" selon les cas.


                T D[] déclare un tableau, pas un pointeur. Regarde une des nombreuses références à ce sujet que tu pourras trouver un peu partout sur les tableaux != pointeurs.

                Citation


                Citation

                si tu dépasse, il y'a une chance que tu atteigne la mémoire d'un autre programme et la , bonjour le plantage.


                Le DOS est mort depuis longtemps.


                Je parlais d'un plantage du programme, pas de l'OS heing ^^</citation>
                Non, mais les programmes ne partagent pas lamême mémoire sur les systèmes modernes, donc "écrire sur la mémoire d'un autre programme" n'est pas pertinent dans ce cas.
                • Partager sur Facebook
                • Partager sur Twitter
                  20 juillet 2007 à 9:58:53

                  J'ajoute pour la simple culture générale que la raison pour laquelle le code posté plus haut est valide est qu'il fallait garder la compatibilité avec le C.
                  En effet, en C il est courant d'écrire:

                  void func(char *);

                  func("abc");
                   

                  Si cette exception n'existait pas, il est probablement que beaucoup de code C ne compilerait pas sans modifications.
                  • Partager sur Facebook
                  • Partager sur Twitter
                    20 juillet 2007 à 10:13:22

                    Citation

                    Non, mais les programmes ne partagent pas lamême mémoire sur les systèmes modernes, donc "écrire sur la mémoire d'un autre programme" n'est pas pertinent dans ce cas.


                    A ce que je crois, chaque adresse est unique dans toute la mémoire vive
                    exemple: le programme 1 alloue de la memoire de l'octet 2900 a 3000 et le programme 2 alloue de 3001 a 3100.
                    Si le programme 1 déborde, il accedede a l'octet 3001, et la, l'OS est obligé d'arreter le programme 1 non ?

                    NB: ce que vient de dire pamaury c'est justement le genre de chose qui me fait dire que tableau=pointeur...
                    Quoi qu'il en soit, ceux qui ont inventé le C ne sont pas clairs
                    • Partager sur Facebook
                    • Partager sur Twitter
                      20 juillet 2007 à 10:28:52

                      Je réctéfie deux choses:
                      -oui dans la mémoire vive, une adresse est unique mais dans les OS actuels on utilise ce que l'on appèle la pagination qui fait que l'on peut isoler physiquement un processus d'un autre et lui faire croire qu'il a 4Gio d'espace d'adresses alors qu'en fait non. Regarde sur Wikipédia par exemple, çà sera plus clair.

                      -non, tableau!=pointeur mais il faut faire attention de quoi l'on parle. Par exemple, il est clair que:

                      char *p1="str";// bon c'est pas valide comme code mais tant pis
                      char p2[4]="str";
                       

                      sont deux objets différents, puisque p1 est un pointeur vers la chaîne constante "str" alors que p2 est un tableau QUE L'ON PEUT MODIFIER qui est initialiser à "str":
                      -la première alloue sizeof(char*) octets pour stocker un pointeur(p1)
                      -la second alloue 4*sizeof(char) octets pour stocker "str" et p2 pointe vers cette zone

                      La confusion vient du fait-à mon avis-que en effet, p1 et p2 sont deux pointeurs en un sens mais qui ne pointent pas du tout vers le même type de stockage, p1 pointe vers du stockage en lecture-seule alors que p2 pointe vers du stockage en lecture-écriture.
                      L'autre confusion vient mon avis du fait que l'on passe en paramètre toutes les chaînes de caractères par pointeur même si c'est un tableau.
                      • Partager sur Facebook
                      • Partager sur Twitter
                        20 juillet 2007 à 10:35:04

                        > Quoi qu'il en soit, ceux qui ont inventé le C ne sont pas clairs
                        La norme est claire là-dessus.

                        La confusion pointeur/tableau vient du fait que dans quasiment tous les cas, une _expression_ de type tableau dégénère en pointeur.

                        > En effet, en C il est courant d'écrire:
                        Il était surtout courant dans le temps. Mais tu as raison sur le fait que la plupart des programmeurs C n'accordent pas une importance primodiale aux qualificateurs, s'ils peuvent aider, tant mieux, sinon, tant pis.
                        • Partager sur Facebook
                        • Partager sur Twitter
                          20 juillet 2007 à 10:55:51

                          Citation : pamaury

                          -la première alloue sizeof(char*) octets pour stocker un pointeur(p1)
                          -la second alloue 4*sizeof(char) octets pour stocker "str" et p2 pointe vers cette zone



                          Il me semble avoir lu que la taille d'un pointeur en mémoire est identique à la taille d'un int
                          • Partager sur Facebook
                          • Partager sur Twitter
                            20 juillet 2007 à 11:03:25

                            Encore un mythe...
                            Plus sérieusement, non et le contre exemple est simple:
                            sur une plateforme 64-bit, un pointeur fait 8 octets et un int 4 octets et un long 8 octets. A priori la taille d'un pointeur n'a rien à voir avec la taille d'un int.
                            • Partager sur Facebook
                            • Partager sur Twitter
                              20 juillet 2007 à 11:23:29

                              Je confirme : sous 64 bits, un pointeur fait toujours 8 octets.

                              Mais alors pour les int et les long, je dirais qu'un seul mot : C'EST LA MERDE !!!!!!!!!
                              Il existe 3 versions différentes de Linux pour le 64 bits : le LP64, le LLP64 et le ILP64 : regardez le lien ci dessous : le tableau dans la 2e partie...

                              http://www.ibm.com/developerworks/library/l-port64.html

                              Sous Windows en revanche (testé sous XP64 et Vista 64), ils ont accordé leur violons : nous sommes dans une équivalence LLP64 (toujours 32 bits pour int et long)
                              • Partager sur Facebook
                              • Partager sur Twitter

                              Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

                                20 juillet 2007 à 17:44:50

                                Citation

                                -la première alloue sizeof(char*) octets pour stocker un pointeur(p1)
                                -la second alloue 4*sizeof(char) octets pour stocker "str" et p2 pointe vers cette zone


                                Mhhh c'est quand même bizarre de modifier de la mémoire sans l'allouer (ou alors il la désalloue juste aprés la déclaration)
                                Mais sinon un pointeur n'est qu'une adresse donc "sizeof(char*)" ou "sizeof(double*)" ça reviendrais au même non ?
                                • Partager sur Facebook
                                • Partager sur Twitter
                                  20 juillet 2007 à 18:15:56

                                  Certes oui la taille d'un pointeur ne varie à priori pas avec le type pointé. Pour ce qui est de la taille alloué, la première déclaration en elle-même n'alloue pas "str", celle-ci est stockée en général dans une section lecture-seule de l'exécutable(j'aurais dû le préciser) alors que la second alloue bien 4 octets sans aucune exception.
                                  Par exemple, si on fait:

                                  char *p1="str";
                                  char *p2="str";
                                  char p3[4]="str";
                                  char p4[4]="sta";
                                   

                                  Alors les allocations sont:
                                  -"str" est placée dans une section lecture-seule de l'exécutable
                                  -p1 est alloué(sizeof(char*)) et pointe vers "str" alloué dans la section lecture-seule
                                  -p2 est alloué(sizeof(char*)) et pointe vers le même "str" de la section lecture-seule (les compilateurs détectent lorsque l'on réutilise les même chaînes litérales)
                                  -p3 est alloué(4*sizeof(char*)) et est remplie avec {'s','t','r','\0'}
                                  -p4 est alloué(4*sizeof(char*)) et est remplie avec {'s','t','a','\0'}

                                  Evidemment, on remarquera qu'il est extremmement dangereux de laisser p1 et p2 pointer vers de la mémoire en lecture seule mais c'est ainsi que çà marche, normalement on devrait mettre "const char *".
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    21 juillet 2007 à 9:22:05

                                    > Certes oui la taille d'un pointeur ne varie à priori pas avec le type pointé.

                                    Rien ne garantie ça. Cela pourrait varier, par exemple, du fait de l'alignement, certains types ayant des adresses exprimées en multiples de leur alignement et non d'octets. En revanche, en C tous les types de pointeurs vers des struct ont même représentation (et donc taille). Une règle équivalente existe pour les union.

                                    > (les compilateurs détectent lorsque l'on réutilise les même chaînes litérales)

                                    À ma connaissance, rien ne les y oblige.
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      21 juillet 2007 à 11:03:31

                                      Rien ne les obligent mais la majorité le font.
                                      Pour l'alignement, je n'était pas en train de dire que les pointeurs AVAIENT la même taille, j'ai dis qu'ils avaient A PRIORI la même taille(je dis çà car sur la plupart des architecture la taille d'un pointeur ne varie pas).
                                      Sur quelle(s) architecture(s) est-ce que l'on stocke des pointeurs exprimés en multiples de leur alignement ?
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        21 juillet 2007 à 12:15:26

                                        Citation : pamaury

                                        Rien ne les obligent mais la majorité le font.
                                        Pour l'alignement, je n'était pas en train de dire que les pointeurs AVAIENT la même taille, j'ai dis qu'ils avaient A PRIORI la même taille(je dis çà car sur la plupart des architecture la taille d'un pointeur ne varie pas).
                                        Sur quelle(s) architecture(s) est-ce que l'on stocke des pointeurs exprimés en multiples de leur alignement ?


                                        Personnellement, je n'ai jamais eu l'occasion de travailler sur tant d'archis que ça mais sur c.l.c ils en parlent d'expérience, parfois. Enfin, c'étaient des précisions, rien de plus.
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          22 juillet 2007 à 1:20:17

                                          Bon bin merci beaucoup pour ce débat parce que la différence entre un char* et un char[] m'était toujours restée en travers de la gorge, j'ai toujours eu l'impression qu'il y avait quelque chose de pas clair avec les chaînes de caractères. Je continue de le penser, mais ça va quand même bien mieux :)
                                          • Partager sur Facebook
                                          • Partager sur Twitter

                                          Le saviez-vous... ??

                                          × 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