Comment incrémenter une adresse de pointeur et une valeur de pointeur?

96

Supposons,

int *p;
int a = 100;
p = &a;

Que fera réellement le code suivant et comment?

p++;
++p;
++*p;
++(*p);
++*(p);
*p++;
(*p)++;
*(p)++;
*++p;
*(++p);

Je sais, c'est un peu compliqué en termes de codage, mais je veux savoir ce qui se passera réellement lorsque nous coderons comme ça.

Remarque: Supposons que l'adresse de a=5120300, il est stocké dans le pointeur pdont l'adresse est 3560200. Maintenant, quelle sera la valeur de p & aaprès l'exécution de chaque instruction?

Dinesh
la source
3
pourquoi ne pas l'exécuter dans le débogueur?
AndersK
24
Eh bien ... pourquoi ne pas simplement essayer et voir? printfimprimera un pointeur avec% p
Brian Roach
Si vous êtes curieux de savoir ce qu'il en est, jouez avec. Écrivez simplement un programme c simple qui passe par tous ces cas d'utilisation et voyez si cela a du sens pour vous.
Cyrus
@AndersK. Peut-être que l'OP attend un comportement indéfini? ...Ou peut être pas.
Mateen Ulhaq

Réponses:

177

Premièrement, l'opérateur ++ a priorité sur l'opérateur *, et les opérateurs () ont priorité sur tout le reste.

Deuxièmement, l'opérateur numérique ++ est le même que l'opérateur nombre ++ si vous ne les attribuez à rien. La différence est que nombre ++ renvoie le nombre, puis incrémente le nombre, et ++ le nombre s'incrémente d'abord, puis le renvoie.

Troisièmement, en augmentant la valeur d'un pointeur, vous l'incrémentez de la taille de son contenu, c'est-à-dire que vous l'incrémentez comme si vous répétiez dans un tableau.

Donc, pour résumer le tout:

ptr++;    // Pointer moves to the next int position (as if it was an array)
++ptr;    // Pointer moves to the next int position (as if it was an array)
++*ptr;   // The value of ptr is incremented
++(*ptr); // The value of ptr is incremented
++*(ptr); // The value of ptr is incremented
*ptr++;   // Pointer moves to the next int position (as if it was an array). But returns the old content
(*ptr)++; // The value of ptr is incremented
*(ptr)++; // Pointer moves to the next int position (as if it was an array). But returns the old content
*++ptr;   // Pointer moves to the next int position, and then get's accessed, with your code, segfault
*(++ptr); // Pointer moves to the next int position, and then get's accessed, with your code, segfault

Comme il y a beaucoup de cas ici, j'ai peut-être fait une erreur, veuillez me corriger si je me trompe.

ÉDITER:

Donc je me suis trompé, la précédence est un peu plus compliquée que ce que j'ai écrit, regardez-la ici: http://en.cppreference.com/w/cpp/language/operator_precedence

félipème
la source
6
* ptr ++, la valeur n'est pas incrémentée, le pointeur l'est. Ces opérateurs unaires ont la même priorité mais ils sont évalués de droite à gauche. Le code signifie "prendre le contenu d'où ptr pointe, puis incrémenter ptr". C'est du code C très courant (et oui, assez déroutant). Veuillez corriger cela et je supprimerai le vote défavorable. Idem pour * (ptr) ++, la parenthèse ne fait rien.
Lundin
Merci beaucoup Lundin, ai-je manqué autre chose?
felipemaia
@Lundin Salut, la réponse ci-dessus est-elle corrigée maintenant? Merci.
Unheilig
4
@Unheilig La première phrase est encore complètement fausse, postfix ++ prime sur unaire * qui a la même priorité que prefix ++. En dehors de cela, cela semble correct.
Lundin
4
@felipemaia Etes-vous sûr qu'il segfault? Peut-être que c'est juste un comportement indéfini?
jotik
14

vérifié le programme et les résultats sont comme,

p++;    // use it then move to next int position
++p;    // move to next int and then use it
++*p;   // increments the value by 1 then use it 
++(*p); // increments the value by 1 then use it
++*(p); // increments the value by 1 then use it
*p++;   // use the value of p then moves to next position
(*p)++; // use the value of p then increment the value
*(p)++; // use the value of p then moves to next position
*++p;   // moves to the next int location then use that value
*(++p); // moves to next location then use that value
Sujith R Kumar
la source
2
@alex utilise cela signifie, par exemple, considérer l'instruction, 'int * a = p ++;' Ici, la première valeur du pointeur «p» sera utilisée et ensuite p se déplacera à la position suivante. Donc, en effet, après l'exécution de l'instruction ci-dessus, 'a' aura l'adresse de l'emplacement précédent pointé par 'p' et 'p' pointera vers la position suivante. C'est d'abord utiliser la valeur de 'p' pour l'expression d'affectation comme ci-dessus, puis incrémenter la valeur de 'p' pour pointer vers la position suivante
Sujith R Kumar
En bref, je pense qu'il utilise l'expression «utiliser» pour le terme plus formel «assigner». C'est tout.
Apekshik Panigrahi
4

Ce qui suit est une instanciation des diverses suggestions «il suffit de l'imprimer». J'ai trouvé cela instructif.

#include "stdio.h"

int main() {
    static int x = 5;
    static int *p = &x;
    printf("(int) p   => %d\n",(int) p);
    printf("(int) p++ => %d\n",(int) p++);
    x = 5; p = &x;
    printf("(int) ++p => %d\n",(int) ++p);
    x = 5; p = &x;
    printf("++*p      => %d\n",++*p);
    x = 5; p = &x;
    printf("++(*p)    => %d\n",++(*p));
    x = 5; p = &x;
    printf("++*(p)    => %d\n",++*(p));
    x = 5; p = &x;
    printf("*p++      => %d\n",*p++);
    x = 5; p = &x;
    printf("(*p)++    => %d\n",(*p)++);
    x = 5; p = &x;
    printf("*(p)++    => %d\n",*(p)++);
    x = 5; p = &x;
    printf("*++p      => %d\n",*++p);
    x = 5; p = &x;
    printf("*(++p)    => %d\n",*(++p));
    return 0;
}

Il retourne

(int) p   => 256688152
(int) p++ => 256688152
(int) ++p => 256688156
++*p      => 6
++(*p)    => 6
++*(p)    => 6
*p++      => 5
(*p)++    => 5
*(p)++    => 5
*++p      => 0
*(++p)    => 0

J'ai converti les adresses du pointeur en ints afin de pouvoir les comparer facilement.

Je l'ai compilé avec GCC.

Rico Picone
la source
1
Je changerais cela pour inclure la valeur de x et p après l'opération.
NetJohn
3

En ce qui concerne "Comment incrémenter une adresse de pointeur et une valeur de pointeur?" Je pense que cela ++(*p++);est en fait bien défini et fait ce que vous demandez, par exemple:

#include <stdio.h>

int main() {
  int a = 100;
  int *p = &a;
  printf("%p\n",(void*)p);
  ++(*p++);
  printf("%p\n",(void*)p);
  printf("%d\n",a);
  return 0;
}

Il ne s'agit pas de modifier la même chose deux fois avant un point de séquence. Je ne pense pas que ce soit un bon style pour la plupart des utilisations - c'est un peu trop cryptique à mon goût.

Flexo
la source
En fait, les parenthèses sont inutiles: ++*p++incrémenteront avec succès la valeur et le pointeur (le suffixe ++se lie plus fort que le déréférencement *, et cela se produit avant le préfixe en ++raison de l'ordre). Les parenthèses ne sont nécessaires que lorsque vous avez besoin de la valeur avant de l'incrémenter (*p++)++. Si vous choisissez tout préfixe, ++*++pcela fonctionnera très bien sans parenthèses (mais incrémentez la valeur pointée après l'incrément du pointeur).
cmaster
1
        Note:
        1) Both ++ and * have same precedence(priority), so the associativity comes into picture.
        2) in this case Associativity is from **Right-Left**

        important table to remember in case of pointers and arrays: 

        operators           precedence        associativity

    1)  () , []                1               left-right
    2)  *  , identifier        2               right-left
    3)  <data type>            3               ----------

        let me give an example, this might help;

        char **str;
        str = (char **)malloc(sizeof(char*)*2); // allocate mem for 2 char*
        str[0]=(char *)malloc(sizeof(char)*10); // allocate mem for 10 char
        str[1]=(char *)malloc(sizeof(char)*10); // allocate mem for 10 char

        strcpy(str[0],"abcd");  // assigning value
        strcpy(str[1],"efgh");  // assigning value

        while(*str)
        {
            cout<<*str<<endl;   // printing the string
            *str++;             // incrementing the address(pointer)
                                // check above about the prcedence and associativity
        }
        free(str[0]);
        free(str[1]);
        free(str);
Abhishek DK
la source
Qu'est-ce que l'asociativité?
71GA
1
dans le code, vous pouvez voir le * str ++, maintenant ici les deux * et ++ ont la même priorité (même priorité en terme profane) et aussi * str ++ ne sont pas séparés en utilisant des parenthèses comme * (str ++) ou (* str) ++, donc il devient nécessaire de savoir comment il doit être évalué. donc de droite à gauche signifie (x = str ++) puis (y = * x)
Abhishek DK