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 :

Petits problèmes de pointeurs


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    152
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 152
    Par défaut Petits problèmes de pointeurs
    Salut,

    Alors voilà, j'ai des instructions sur les pointeurs que je ne comprend pas bien.
    Je les ai écris :
    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
    #include <stdio.h>
     
    int main(){
      int a[] = {12,23,34,45,56,67,78,89,90,100};
      int *p, (*q)[2];
      p=a;
      q = (int (*)[2])&a;
     
      printf("%p %p %p\n",a,&p,&q);
     
      printf("%d\n", *p+2);  //14
      printf("%d\n", *(p+2)); //34
      printf("%p\n", &p+1);
      printf("%p\n",&a[4]);
      printf("%p\n",&a[4]-3);
      printf("%p\n",a+3);
      printf("%d\n",&a[7]-p);
      printf("%p\n",p+(*p-10));
      printf("%d\n",*(p+*(p+8)-a[7])); //23
      printf("%d\n",(*q)[3]);
      printf("%p\n",q+2);
      printf("%d\n",(*(q+3))[1]);
      return 0;
    }
    Dans un premier temps j'ai hésiter à me sucider en me coupant les veines avec la feuille d'exam (c'était bien dans un exam de c) ... et dans un second temps aussi ... Mais bon j'ai quand même réussi à comprendre certaines instruction (3 avec les "//" et qqunes avec les adresses). J'ai alors plusieurs questions :
    - que fait l'instruction qui affecte q ?
    - que se passe t-il quand on ajoute 3 a une adresse ? Genre &a[4]-3 ou a+3 , comment expliqueriez vous ce résultat ?
    - que font les 3 dernières instructions exactement ?

    Après avoir regardé qq cours sur les pointeurs, je ne trouve toujours pas réponses à ces questions ... Si qqun pourrait m'éclairer je serai très reconnaissant.

    Merci d'avance.

    Edit : j'ai oublié de vous donner les résultats de ce prog :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    0xbfdb8d60 0xbfdb8d8c 0xbfdb8d88
    14
    34
    0xbfdb8d90
    0xbfdb8d70
    0xbfdb8d64
    0xbfdb8d6c
    7
    0xbfdb8d68
    23
    45
    0xbfdb8d70
    89

  2. #2
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 493
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 493
    Billets dans le blog
    1
    Par défaut
    Tu avais toutes ces instructions et devais dire ce que chacune fait (ou affiche) ?

    - que se passe t-il quand on ajoute 3 a une adresse ? Genre &a[4]-3 ou a+3 , comment expliqueriez vous ce résultat ?
    C'est la base de l'arithmétique des pointeurs. Quand tu incrémentes un pointeur, tu te décales de façon à pointer sur l'emplacement mémoire suivant, en considérant la mémoire comme une suite d'emplacement du type pointé.
    Exemple : soit pa pointeur sur int, alors pa+1 pointe sur l'entier suivant après *pa.

    - que fait l'instruction qui affecte q ?
    &a est n'est pas du même type que q, il faut donc caster la valeur pour obtenir des types concordants, sinon, tu auras un warning à la compilation :
    d:\...\test.c|76|warning: assignment from incompatible pointer type|
    - que font les 3 dernières instructions exactement ?
    Quelque d'assez obscur pour moi, il faut encore que je réfléchisse là-dessus

  3. #3
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 493
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 493
    Billets dans le blog
    1
    Par défaut
    En espérant ne pas m'être trompé

    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
    #include <stdio.h>
     
    int main(void){
      int a[] = {12,23,34,45,56,67,78,89,90,100};
      int *p, (*q)[2];
      p=a;
      q = (int (*)[2])&a;
     
      printf("a = %p \t&p = %p \t&q = %p\n",a,&p,&q);
     
      printf("%d\n", *p+2);  //14
      printf("%d\n", *(p+2)); //34
      printf("%p\n", &p+1); // adresse de p + taille d'un pointeur (4 octets)
      printf("%p\n",&a[4]); // adresse du 5e element (a +16 octets)
      printf("%p\n",&a[4]-3); // adresse du 2e element (a + 4 octets)
      printf("%p\n",a+3);   // adresse du <s>3e</s> 4e elements (a + 12 octets)
      printf("%d\n",&a[7]-p); // a + 7 - a = 7
      printf("%p\n",p+(*p-10)); //p+12-10 = p+2 = a+2
      printf("%d\n",*(p+*(p+8)-a[7])); //23
     
     
        puts("\nLe coquinou de 'q'...");
        /* q est un pointeur sur un tableau de 2 ints
        Voir http://www.developpez.net/forums/d1177939/c-cpp/c/tableaux-string/#post6467166 */
     
        printf("q vaut  %p qui est bien l'adresse du debut du tableau 'a'\n" , q);
     
        printf("1=%d  2=%d\n",(*q)[0], (*q)[1] ); //
        printf("%d\n",(*q)[3]); // logique avec la ligne du dessus
     
        printf("sizeof(*q) = %d\n", sizeof(*q));
        printf("%p\n",q+2);   // q decale de 2 fois ce qu'il pointe.
                            // il pointe un tableau de 2 ints donc 4*2 octets
                            // on se decale 2 fois donc 16 octets au total
     
        printf("%d\n",(*(q+3))[1]); // en combinant les precedentes explications
                                    // on obtient bien le 8e element de a, soit a[7]
        printf("Pour verifier, a[7] = %d\n\n", a[7]);
      return 0;
    }

  4. #4
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    152
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 152
    Par défaut
    Merci pour vos réponses, mais j'ai encore qq soucis ^^

    Citation Envoyé par Bktero Voir le message
    C'est la base de l'arithmétique des pointeurs. Quand tu incrémentes un pointeur, tu te décales de façon à pointer sur l'emplacement mémoire suivant, en considérant la mémoire comme une suite d'emplacement du type pointé.
    Exemple : soit pa pointeur sur int, alors pa+1 pointe sur l'entier suivant après *pa.
    Ok, si on affiche avec %p on obtient donc l'adresse du prochain élément.

    Ensuite : &a[7]-p , je n'ai pas très bien compris le a + 7 - a. Normalement quand on fait a[7] on obtient pas l'élément en 7ème position ? Donc &a[7] ça devrait être l'adresse de cet élément non ?

    Aussi, à propos de l'affectation de q, si j'ai bien compris c'est un tableau de 2 int dont le début est le début de a ? Donc si on veut faire par exemple
    Ca affichera a[3] ? Même si c'est hors limite de q ?

    Les dernières instructions ont encore un peu du mal à être acceptées par ma cervelle, je reviendrais là dessus sans doutes x)

    Encore merci.

    PS : J'ai eu la liste des printf dans l'exam, il fallait juste dire ce que ça affichait. Je ne vous cacherais pas que cet exam ne ma pas trop inspiré :v

  5. #5
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 493
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 493
    Billets dans le blog
    1
    Par défaut
    Ensuite : &a[7]-p , je n'ai pas très bien compris le a + 7 - a. Normalement quand on fait a[7] on obtient pas l'élément en 7ème position ? Donc &a[7] ça devrait être l'adresse de cet élément non ?
    Oui c'est ça

    Il faut savoir que a est le nom du tableau, mais que si tu utilises a dans le code (seul, sans crochet derrière), il est automatiquement converti en &a[0]. Il faut aussi savoir que a[1] est égal à *(a+1).

    p étant égal à a (p contient l'adresse du premier élément du tableau, il contient &a[0]), on a : &a[7] - p = &*(a+7) - a = a +7 - a = 7.


    Aussi, à propos de l'affectation de q, si j'ai bien compris c'est un tableau de 2 int dont le début est le début de a ?
    Non, q est un pointeur vers un tableau de 2 entiers. Regarde le lien que j'ai donné en commentaire dans le code précédent.

    Comme q est un pointeur sur un tableau (de 2 entiers), il faut bien l'initialiser avec &a et non a (je te passe le transtypage dont j'ai déjà parlé).

    *q est égal à a, en toute logique et par conséquent.

    Ca affichera a[3] ?
    Tu essayeras

    Même si c'est hors limite de q ?
    Les limites c'est toujours une chose floue en C. q n'a pas de limite, c'est un pointeur vers un endroit donné de la mémoire. Tu peux le faire pointer où tu as envie, mais à cet endroit :
    • il se pourrait que tu lises n'importe quoi
    • il se pourrait qu'écrire provoque un crash (segmentation fault) ou un comportement tout à fait improbable

  6. #6
    Membre du Club
    Profil pro
    Inscrit en
    Juin 2012
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Juin 2012
    Messages : 10
    Par défaut
    Bonjour à tous.

    Je lis avec intérêt ce thread et ne comprends pas un point.

    Normalement lorsque l'ont fait :
    pour obtenir l'adresse du 8e élément, on ne rajoute pas réellement 7 à l'adresse maisnon ?

    Donc pourquoi lorsque l'ont fait
    obtient-on 7 et non pas
    ?

    Edit : En fait ma question c'est : pourquoi le compilateur s'occupe-t-il lui même de ce calcul ?

  7. #7
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 026
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 026
    Par défaut
    Quand tu as un pointeur, tu peux faire :
    - p++ pour pointer sur l'élément suivant
    - p-- pour pointer sur l'élément précédant
    - p += x pour pointer sur le x ième élément suivant
    - p -= x pour pointer sur le x ième élément précédant
    - pointeur début - pointeur fin : nombre d'élément.

    C'est beaucoup plus pratique que de devoir à chaque fois écrire sizeof tu ne trouves pas?
    De plus ceci évite certaines erreurs (comme pointer sur un int puis pointer un octet plus loin).

    L'autre raison, c'est qu'il n'y a aucun intérêt à incrémenter/décrémenter un pointeur d'un octet quelque soit le type.
    Or pointer x éléments après ou avant est très utile dans les parcours de tableaux etc...

  8. #8
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 493
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 493
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par stroke Voir le message
    Normalement lorsque l'ont fait :
    pour obtenir l'adresse du 8e élément, on ne rajoute pas réellement 7 à l'adresse maisnon ?

    Donc pourquoi lorsque l'ont fait
    obtient-on 7 et non pas
    ?
    Ecrire a+7 est implicitement transformé par le compilateur en a + (7 * sizeof(int)), et même plus probablement en a + (7 * sizeof(*a)). Pour l'opération inverse, je pense que c'est surtout pour une question de cohérence. Posons que int *b = a + 7. Il serait logique que le test b - a == 7 soit vrai. De même, il serait cohérent qu'il fasse le calcul implicitement dans les 2 sens. Pour le programmeur, ce qui importe n'est pas tant le décalage réel en mémoire mais le décalage en terme d'objets, comme l'a dit Neckara.



    Je regarde la correction de diogene, j'ai fait une faute (pour *(a+3))... Je m'en sors bien ^^

  9. #9
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    int *p, (*q)[2] : p est un pointeur sur int, q est un pointeur sur un tableau de 2 int
    
    p=a        :   p contient l'adresse du premier élément du tableau a
    
    q = (int (*)[2])&a : q contient l'adresse d'un tableau de 2 éléments (int), cette adresse étant celle du tableau a (de 10 int, d'où le cast). 
                         (But probable : présenter a comme un tableau à 2 dimensions q[5][2])
    
    ...a,&p,&q : affichage de l'adresse du premier élément (n°0) de a, de l'adresse du pointeur p et de celle du pointeur q
    
    ...*p+2    : Equivalent à p[0]+2 : affichage de l'entier à l'adresse p auquel on a ajouté 2.(p==a)-> a[0]+2 -> 14 
    
    ...*(p+2)  : Equivalent à p[2] : affichage de l'entier n°2 du tableau débutant à l'adresse p. (p==a) a[2]-> 34.
    
    ...&p+1    : Adresse de p augmentée de 1. 
                 Comme p est du type int *, la position mémoire de p sera augmentée de sizeof(int*) 
    
    ...&a[4]   : Equivalent à &*(a+4) == a+4 . 
                 L'adresse correspond à celle de l'élément n°4 de a 
                (position mémoire : celle de a augmentée de 4*sizeof(int))
    
    ...&a[4]-3 : Equivalent à &*(a+4)-3 == a+4-3 == a+1 . 
                 L'adresse correspond à celle de l'élément n°1 de a 
                (position mémoire : celle de a augmentée de sizeof(int))
    
    ...a+3     : L'adresse correspond à celle de l'élément n°3 de a 
                (position mémoire : celle de a augmentée de 3*sizeof(int))
    
    ...&a[7]-p : Equivalent à &*(a+7)-p == a+7-p ; avec p==a -> 7
    
    ...p+(*p-10) : *p ==*a == a[0] == 12. Donc égal à p+(12-10) == p+2. 
                   L'adresse correspond à celle de l'élément n°2 de p (ou de a) 
                  (position mémoire : celle de a augmentée de 2*sizeof(int))
    
    ...*(p+*(p+8)-a[7]): Equivalent à *(p+p[8]-a[7]) == p[p[8]-a[7]]. 
                         (p==a) -> a[a[8]-a[7]] == a[1] == 23
    
    ...(*q)[3]  :  Equivalent à q[0][3]. Comme q[0] == a  -> a[3]  == 45
    
    ...q+2      : adresse de l'élément n°2 de q. Les éléments de q sont des tableaux de 2 int, 
                  (position mémoire : celle de q (ou a) augmentée de 2*sizeof(int[2]) ==  4*sizeof(int)) 
    
    ...(*(q+3))[1] : Equivalent à q[3][1] ; 
                     q[3] : Ce tableau (de 2 int) correspond à la position de l'élément n°6 (=3*2) de a 
                     (q[0]==a); q[3][1] est l'élément n°7 de a (a[7]) -> 89

  10. #10
    Membre chevronné

    Profil pro
    Inscrit en
    Août 2007
    Messages
    179
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 179
    Par défaut
    Citation Envoyé par Raikyn Voir le message
    - que font les 3 dernières instructions exactement ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    printf("%d\n",(*q)[3]);
    Là a priori c'est relativement simple "q" étant initialisé comme l'adresse de "a", la 4ème valeur du tableau s'affiche

    Là ça commence à être un peu plus tordu, on obtiend l'adresse "a" ("q") décalée deux fois mais comme "q" est déclaré non pas comme un entier mais comme un tableau de deux entier ça donne q + 2 * 2 * (taille en octet d'un entier (en général 4))

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    printf("%d\n",(*(q+3))[1]);
    Là c'est vachement tordu mais si on a en tête le truc de dessus c'est assez logique : on décale 3 fois, chaque décalage faisant 2 entiers on arrive au 7éme élément du tableau, du coup à la position "[1]" on tombe sur le 8ème élément soit 89

    Edit : ah, grillé par Bktero, bon visiblement on est assez d'accord c'est plutôt bon signe, mais c'est clair que c'etait pas trivial comme question

  11. #11
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 493
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 493
    Billets dans le blog
    1
    Par défaut
    On a effectivement l'air d'accord

Discussions similaires

  1. Réponses: 22
    Dernier message: 14/04/2014, 00h02
  2. Petit problème de pointeur
    Par Bebuck dans le forum Débuter
    Réponses: 9
    Dernier message: 12/02/2012, 05h19
  3. Petit problème sur pointeurs de structures
    Par benjaminb dans le forum C
    Réponses: 5
    Dernier message: 05/01/2008, 20h08
  4. Réponses: 4
    Dernier message: 15/10/2006, 18h05
  5. petit problème avec pointeurs
    Par Kerod dans le forum C
    Réponses: 12
    Dernier message: 09/12/2005, 15h48

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