61 votes

++ sur un pointeur déréférencé en C?

En essayant de comprendre le comportement des pointeurs en C, j'ai été un peu surpris par ce qui suit (exemple de code ci-dessous):

 #include <stdio.h>

void add_one_v1(int *our_var_ptr)
{
    *our_var_ptr = *our_var_ptr +1;
}

void add_one_v2(int *our_var_ptr)
{
    *our_var_ptr++;
}

int main()
{
    int testvar;

    testvar = 63;
    add_one_v1(&(testvar));         /* try first version of the function */
    printf("%d\n", testvar);        /* prints out 64                     */
    printf("@ %p\n\n", &(testvar));

    testvar = 63;
    add_one_v2(&(testvar));         /* try first version of the function */
    printf("%d\n", testvar);        /* prints 63 ?                       */
    printf("@ %p\n", &(testvar));   /* address remains identical         */
}

/*

OUTPUT:

64
@ 0xbf84c6b0

63
@ 0xbf84c6b0

*/
 

Ma question est: que fait exactement l'instruction *our_var_ptr++ dans la deuxième fonction ( add_one_v2 ) car ce n'est clairement pas la même chose que *our_var_ptr = *our_var_ptr +1 ?

78voto

Mark Ransom Points 132545

C'est l'un de ces petits gotcha qui font le C et le C++ donc, beaucoup de plaisir. Si vous voulez plier votre cerveau, figure celui-ci:

while (*dst++ = *src++) ;

C'est une copie de chaîne. Les pointeurs reçois incrémenté jusqu'à ce qu'un personnage avec une valeur de zéro est copié. Une fois que vous savez pourquoi cette astuce fonctionne, vous ne serez jamais oublier comment ++ fonctionne sur les pointeurs de nouveau.

P. S. Vous pouvez toujours remplacer l'opérateur commande avec des parenthèses. Le suivant va incrémenter la valeur pointée, plutôt que le pointeur lui-même:

(*our_var_ptr)++;

47voto

htw Points 10312

En raison de règles de priorité des opérateurs et le fait qu' ++ est un suffixe de l'opérateur, add_one_v2() ne déréférencer le pointeur, mais l' ++ est appliquée pour le pointeur lui-même. Cependant, rappelez-vous que C utilise toujours passer par valeur: add_one_v2() est l'incrémentation de sa copie locale du pointeur, qui auront aucun effet sur la valeur stockée à cette adresse.

Comme un test, remplacez - add_one_v2() avec ces bouts de code et de voir comment la sortie est affectée:

void add_one_v2(int *our_var_ptr)
{
    (*our_var_ptr)++;  // Now stores 64
}

void add_one_v2(int *our_var_ptr)
{
    *(our_var_ptr++);  // Increments the pointer, but this is a local
                       // copy of the pointer, so it doesn't do anything.
}

43voto

CodeSlave Points 7133

OK,

*our_var_ptr++;

il fonctionne comme ceci:

  1. Le déréférencement qui se passe en premier, vous donnant l'emplacement de mémoire indiqué par our_var_ptr (qui contient 63).
  2. Ensuite, l'expression est évaluée, le résultat de 63 ans, est encore 63.
  3. Le résultat est jeté (vous ne faites pas n'importe quoi avec elle).
  4. our_var_ptr est ensuite incrémenté APRÈS l'évaluation.

C'est effectivement la même chose comme cela:

*our_var_ptr;
our_var_ptr = our_var_ptr + 1;

Un sens? Marque Rançon de la réponse est un bon exemple de cela, sauf qu'il utilise en fait le résultat.

8voto

dmckee Points 50318

Beaucoup de confusion ici, voici donc une modification de programme de test à faire de ce qui se passe transparent (ou au moins clair*er*):

#include <stdio.h>

void add_one_v1(int *p){
  printf("v1: pre:   p = %p\n",p);
  printf("v1: pre:  *p = %d\n",*p);
    *p = *p + 1;
  printf("v1: post:  p = %p\n",p);
  printf("v1: post: *p = %d\n",*p);
}

void add_one_v2(int *p)
{
  printf("v2: pre:   p = %p\n",p);
  printf("v2: pre:  *p = %d\n",*p);
    int q = *p++;
  printf("v2: post:   p = %p\n",p);
  printf("v2: post:  *p = %d\n",*p);
  printf("v2: post:   q = %d\n",q);
}

int main()
{
  int ary[2] = {63, -63};
  int *ptr = ary;

    add_one_v1(ptr);         
    printf("@ %p\n", ptr);
    printf("%d\n", *(ptr));  
    printf("%d\n\n", *(ptr+1)); 

    add_one_v2(ptr);
    printf("@ %p\n", ptr);
    printf("%d\n", *ptr);
    printf("%d\n", *(ptr+1)); 
}

avec le résultat obtenu:

v1: pre:   p = 0xbfffecb4
v1: pre:  *p = 63
v1: post:  p = 0xbfffecb4
v1: post: *p = 64
@ 0xbfffecb4
64
-63

v2: pre:   p = 0xbfffecb4
v2: pre:  *p = 64
v2: post:  p = 0xbfffecb8
v2: post: *p = -63
v2: post:  q = 64

@ 0xbfffecb4
64
-63

Quatre choses à noter:

  1. les modifications à la copie locale de l'indicateur sont pas reflétés dans l'appel de pointeur.
  2. des modifications à la cible du pointeur n'affectent la cible de l'appel pointeur (au moins jusqu'à ce que la cible du pointeur est mis à jour)
  3. la valeur pointée en add_one_v2 est pas incrémenté, et ni est la valeur suivante, mais le pointeur est
  4. l'incrémentation du pointeur de la souris en add_one_v2 qui se passe après le déréférencement

Pourquoi?

  • Parce qu' ++ lie plus étroitement que d' * (comme déréférencement ou multiplication) donc l'augmentation de la add_one_v2 s'applique à l'aide du pointeur, et pas ce que c'points.
  • post par incréments de se produire après l'évaluation de la durée, de sorte que le déréférencement obtient la première valeur du tableau (élément 0).

7voto

Dave Costa Points 25282

Comme les autres l'ont souligné, la priorité de l'opérateur de provoquer l'expression de la v2 de la fonction pour être considéré comme *(our_var_ptr++).

Cependant, puisque c'est une post-incrémentation de l'opérateur, ce n'est pas tout à fait vrai de dire qu'il incrémente le pointeur et déréférence il. Si cela était vrai, je ne pense pas que vous seriez obtenir 63 comme votre sortie, car il serait de retour la valeur dans le prochain emplacement de mémoire. En fait, je crois que la logique de la séquence des opérations est:

  1. Sauvegarde la valeur courante du pointeur
  2. Incrémenter le pointeur
  3. Déréférencer le pointeur de la valeur enregistrée à l'étape 1

Comme htw expliqué, vous ne voyez pas le changement de la valeur du pointeur, car il est passé par valeur à la fonction.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X