Annonce

Réduire
Aucune annonce.

Tableaux et pointeurs

Réduire
X
 
  • Filtre
  • Heure
  • Afficher
Tout nettoyer
nouveaux messages

  • Tableaux et pointeurs

    Bonjour à tous,

    Une petite question à propos du code suivant :

    Code:
    #include <stdlib.h>
    #include <stdio.h>
    
    
    int main(int argc, char **argv)
    {
       int tab[] = {1,2,3};
    
       printf("L'adresse de tab est : %p\n", &tab);
       printf("La valeur de tab est : %p\n", tab);
       printf("L'adresse de la premiere case du tableau est : %p\n\n", &tab[0]);
        return 0;
    }
    C.png

    Est-il normale que la variable "tab" pointe sur sa même adresse, sachant que tab pointe aussi sur le début du tableau.

    De plus, lorsque qu'on lance un "scanf" sur "&tab", le compilateur émet un warning alors que d'après les résultats du code ci-dessus,

    on a exactement la même adresse ?
    deux et deux font cinq

  • #2
    Et si je te dis d'ajouter 1 à cette adresse, et de regarder le résultat, est-ce que ça te met la puce à l'oreille ?

    Commentaire


    • #3
      Et bien si on ajoute 1 à cette adresse, on obtient l'adresse de la deuxième valeur du tableau ?

      Le problème c'est que si la variable "tab" se comporte comme un pointeur sur son premier élément, pourquoi

      contient-il sa propose adresse, sachant que lorsque l'on fera : " *tab"

      On obtiendra bien la valeur du premier élément du tableau alors que "tab" pointe sur lui-même ?
      Dernière modification par shirocen, 13 mai 2015, 18h15.
      deux et deux font cinq

      Commentaire


      • #4
        Pour tout les cas que tu présentes dans ton 1er post ?

        Commentaire


        • #5
          Non, en effet

          Pour :

          Code:
          printf("L'adresse de tab est : %p\n", &tab+1);
          J'obtiens une adresse complétement différente qui n'a pas de lien avec :

          Code:
          printf("L'adresse de tab est : %p\n", &tab);
          mais quel est l'intérêt de stocker un pointeur qui contient sa propre adresse ?
          deux et deux font cinq

          Commentaire


          • #6
            Après quelques test :

            Code:
            #include <stdlib.h>
            #include <stdio.h>
            
            
            int main(int argc, char **argv)
            {
               int tab[] = {1,2,3};
            
               printf("L'adresse de tab est : %p\n", &tab);
               printf("L'adresse de tab1 est : %p\n", &tab+1);
               printf("L'adresse de tab2 est : %p\n", &tab+2);
               printf("La valeur de tab est : %p\n", tab);
                return 0;
            }
            CC.png

            Notre pointeur tab est finalement un pointeur de tableau de 3 int.
            En effet lorsqu'on passe de tab à tab+1 l'adresse s'incrémente de 12
            et sachant qu'un int fait 4 octets, on peu déduire que tab pointe sur un tableau de 3 int.
            deux et deux font cinq

            Commentaire


            • #7
              Attention quand on ajoute 1, faut rester cohérent, le code à tester comparé à ton 1er code serait

              Code:
              #include <stdio.h>
              
              int main(void)
              {
                  int tab[] = {1, 2, 3};
              
                  printf("%p\n", (void *) (tab+1));
                  printf("%p\n", (void *) &(tab[1]));
                  printf("%p\n", (void *) &(tab+1));
              
                  return 0;
              }
              Si tu arrives à compiler, c'est que tu as un soucis avec ton compilateur qui est mal réglé

              Commentaire


              • #8
                Merci pour ton code Fred' ^_^,

                Au 3éme printf il faut juste transformé &(tab+1) en &tab +1 sinon, ça ne compile pas.

                Mais il reste toujours cette question :

                Code:
                #include <stdio.h>
                
                int main(void)
                {
                    int tab[] = {1, 2, 3};
                
                    printf("%p - %p - %p\n", (void *) (tab),(void *) (tab+1),(void *) (tab+2));
                    printf("%p - %p - %p\n", (void *) &(tab[0]),(void *) &(tab[1]),(void *) &(tab[2]));
                    printf("%p - %p - %p\n", (void *) &tab,(void *) &tab+1,(void *) &tab+2);
                
                    return 0;
                }
                CCC.png

                Ici, "tab" contient sa propre adresse, cette même adresse pointe sur la première valeur du tableau ?
                deux et deux font cinq

                Commentaire


                • #9
                  Au 3éme printf il faut juste transformé &(tab+1) en &tab +1 sinon, ça ne compile pas.
                  Bah non t'as pas compris, tout le problème est là, ça ne compile pas, car ce n'est pas cohérent, il est donc normal que tu es cette erreur...

                  Il y a donc sur les trois lignes que tu présentes dans ton 1er post, une ligne qui n'est pas conventionnel car source d'erreur !

                  Commentaire


                  • #10
                    Qu'est-ce qui n'est pas cohérent ?

                    Le fait de demander l'adresse de "tab", ou le fait de vouloir incrémenté cette adresse pour accéder à l'élément suivant ?


                    Finalement, que représente "tab" ?
                    deux et deux font cinq

                    Commentaire


                    • #11
                      J'ai trouvé ceci :

                      Citation : C99 traduit

                      Sauf quand elle est l'opérande de l'opérateur sizeof ou de l'opérateur unaire &, ou est une chaine de caractères littérale utilisée pour initialiser un tableau, une expression de type "tableau de type" est convertie en une expression de type "pointeur de type" qui pointe sur l'élément initial de l'objet tableau et n'est pas une lvalue. Si le tableau est d'une classe de stockage registre, le comportement est indéterminé.

                      Le mot clé, c'est le mot expression.
                      Une expression n'est pas un objet en mémoire, c'est un bout de code source, comme 2+3 , &i , ou simplement tab .
                      Quand il lit l'expression 2+3 , le compilateur peut directement calculer le résultat: 5 (de type int ).
                      Quand il lit l'expression &i , le compilateur génère les instructions machine qui calculent l'adresse de i (de type int* si i est de type int ).
                      Quand il lit l'expression tab , le compilateur génère les instructions machine qui calculent l'adresse de l'élément initial de tab (de type int* si tab est de type int[] ). Sauf avec sizeof , & , et "chaine d'initialisation" , mais c'est le chapitre suivant.

                      Source

                      Donc tab n'existe pas en mémoire, c'est une manière d'accéder au premier élément du tableau, donc comme tu disais plus haut

                      c'est "pas conventionnel" de demandé son adresse :x
                      Dernière modification par shirocen, 13 mai 2015, 19h38.
                      deux et deux font cinq

                      Commentaire


                      • #12
                        tab représente l'adresse du 1er élément du tableau, tu l'as dis tout à l'heure, par contre &tab n'est pas cohérent, plutôt serait &(*tab) qui équivaut à tab équivalent à &(tab[0]), ce qui veut dire que ton &tab représente l'emplacement du tableau et non un élément du tableau, et comme tab est l'adresse du 1er élément, on t'annonce que le tableau se trouve là où se trouve le premier élément.

                        Donc les équivalences concrètes pour l'adresse de l'élément du tableau est &(*tab) == &(tab[0]) == tab

                        L'adresse du tableau est &(tab) et n'est donc pas une ligne cohérente car on souhaite l'adresse d'un élément du tableau.

                        Commentaire


                        • #13
                          Merci beaucoup Fred', pour la petite histoire j'étais sur les buffer overflow et j'ai lu un code qui ma beaucoup perturbé mais qui finalement est faux ou "non conventionnel" :

                          http://www.bases-hacking.org/buffer-overflow.html
                          deux et deux font cinq

                          Commentaire


                          • #14
                            Oui effectivement il a fumé, son scanf est faux dès ses premières lignes de code

                            Commentaire


                            • #15
                              Donc, pour conclure :

                              Lorsqu'on déclare un tableau -> tab[3] = {1,2,3} par exemple, la variable "tab" n'existe pas en mémoire, lorsque que le compilateur va

                              lire l'EXPRESSION tab, il va tout simplement calculé l'adresse de début du tableau et rien d'autre, tab fait donc

                              référence au début de notre tableau, un pointeur sur son premier élément, on peut donc appliquer l'arithmétique de pointeur et

                              incrémenté "tab" pour accéder aux différents éléments du tableau.
                              deux et deux font cinq

                              Commentaire

                              Chargement...
                              X