142 votes

Expressions de pointeur : *ptr++, *++ptr et ++*ptr

Récemment, je suis confronté à ce problème que je suis incapable de comprendre par moi-même.

Que signifient vraiment ces trois expressions ?

*ptr++
*++ptr
++*ptr

J'ai essayé Ritchie. Mais malheureusement, je n'ai pas pu suivre ce qu'il a dit à propos de ces 3 opérations.

Je sais qu'elles sont toutes effectuées pour incrémenter le pointeur/la valeur pointée. Je suppose aussi qu'il peut y avoir beaucoup de choses à propos de la précédence et de l'ordre d'évaluation. Comme l'un incrémente le pointeur d'abord puis récupère le contenu de ce pointeur, l'autre récupère simplement le contenu puis incrémente le pointeur, etc. Comme vous pouvez le voir, je n'ai pas une compréhension claire de leurs opérations réelles, que j'aimerais éclaircir dès que possible. Mais je suis vraiment perdu lorsque j'ai l'occasion de les appliquer dans des programmes. Par exemple :

int main()
{
    char *p = "Hello";
    while(*p++)
         printf("%c",*p);
    return 0;
}

me donne cette sortie :

ello

Mais je m'attendais à ce qu'il imprime Hello . Une dernière demande - Veuillez me donner des exemples de comment chaque expression fonctionne dans un extrait de code donné. Car la plupart du temps, seule une simple théorie me dépasse.

6 votes

Vous avez manqué le quatrième : (*ptr)++ (les parenthèses sont nécessaires pour lever l'ambiguïté avec *ptr++)

15 votes

Parce que vous avez incrémenté le pointeur avant de l'imprimer. Vous vouliez while(*p) et printf("%c", *p++);

0 votes

Super questions pour l'interview. Utilisation pratique limitée. J'aimerais que le langage C n'ait pas ces pointeurs :)

0voto

David R Tribble Points 4813
*ptr++    // 1

Cela revient à:

    tmp = *ptr;
    ptr++;

Ainsi, la valeur de l'objet pointé par ptr est récupérée, puis ptr est incrémenté.

*++ptr    // 2

Cela revient à:

    ++ptr;
    tmp = *ptr;

Ainsi, le pointeur ptr est incrémenté, puis l'objet pointé par ptr est lu.

++*ptr    // 3

Cela revient à:

    ++(*ptr);

Ainsi, l'objet pointé par ptr est incrémenté; ptr reste inchangé.

0voto

Lundin Points 21616
  • Postfix ++ a une plus haute priorité que * unaire.
  • Prefix ++ et * unaire ont la même priorité, les expressions avec les deux ont une associativité des opérateurs de droite à gauche, ce qui signifie que le ou les opérandes à droite se lient à l'opérande avant ceux de gauche.

Par conséquent :

  • *ptr++ Incrémente le pointeur de 1 élément puis dé-référence l'emplacement mémoire qu'il avait avant l'incrémentation.
  • *++ptr Incrémente le pointeur de 1 élément puis dé-référence l'emplacement mémoire où il pointe maintenant.
  • ++*ptr Dé-référence l'emplacement mémoire puis incrémente le contenu (valeur) de celui-ci de 1.

0voto

Peter Schneider Points 1913

Voici une classe qui documente toutes les fonctions pertinentes sur stderr. J'essaie les trois expressions que vous mentionnez dans un programme :

#include 
#include 
using namespace std;

struct PtrT;

ostream& operator<<(ostream& os, const PtrT& ptr);

/// 
/// Une classe qui définit les post- et pre-incréments ainsi que le déréférencement.
/// Elle documente tous les appels de fonctions, y compris les constructeurs et destructeur.
/// 
struct PtrT
{
    string name; //< Fournit une identité.
    int val = 0;

    PtrT(string n) : name(n)
    {
        cerr << "PrT(\"" << name << "\", " << val << "). ";
    }

    /// 
    /// Fait une copie de l'élément de droite, mais préfixe le
    /// nouveau nom avec "copy_of"
    /// 
    PtrT(const PtrT &rhs) : name("copy_of_" + rhs.name), val(rhs.val)
    {
        cerr << "PrT(" << rhs << "). ";
    }

    ~PtrT()
    {
        cerr << "~PrT(" << *this << "). ";
    }

    /// 
    /// Post-incrément, en incrémentant val.
    /// 
    /// Une copie de *this, avec l'ancienne val.
    PtrT operator++(int)
    {
        cerr << "post-incr " << *this << ". ";
        PtrT returnVal(*this);
        ++val;
        cerr << "post-incr : this is now " << *this 
            << ", but will return " << returnVal << ". ";
        return returnVal;
    }

    /// 
    /// Pré-incrément, en incrémentant val
    /// 
    /// *this avec la val incrémentée.
    PtrT& operator++()
    {
        cerr << "pre-incr " << *this << ", val will be " << val + 1 << ". ";
        ++val;
        return *this;
    }

    /// 
    /// Opérateur de "déréférencement"
    /// 
    /// Une référence à val
    int& operator*()
    {
        cerr << "deref " << *this << ". ";
        return val;
    }
};

/// 
/// Fonction de commodité qui affiche le nom avec val entre parenthèses
/// 
ostream& operator<<(ostream& os, const PtrT &ptr)
{
    os << ptr.name << "(" << ptr.val << ")";
    return os;
}

int main()
{
    PtrT p("p");
    cerr << "Before assignment to i: " << p << endl;

    cerr << "\n--------------- *++p ------------------\n";
    // Incrémente p, renvoie une référence à val après l'incrémentation
    int i = *++p; 
    cerr << "i now: " << i << ", " << p << endl;

    cerr << "\n--------------- ++*p ------------------\n";
    // renvoie val, incrémente int via une référence
    i = ++*p; 
    cerr << "i now: " << i << ", " << p << endl;

    cerr << "\n--------------- *p++ ------------------\n";
    // fait une copie de p, incrémente p.val, renvoie une référence à val de la copie de p
    i = *p++;
    cerr << "i now: " << i << ", " << p << endl;
}

L'opérateur de sortie de la classe imprime le nom de l'objet avec la valeur de son membre int, val, entre parenthèses. La sortie du programme est la suivante :

PrT("p", 0). Before assignment to i: p(0)

--------------- *++p ------------------
pre-incr p(0), val will be 1. deref p(1). i now: 1, p(1)

--------------- ++*p ------------------
deref p(1). i now: 2, p(2)

--------------- *p++ ------------------
post-incr p(2). PrT(p(2)). post-incr: this is now p(3), but will return copy_of_p(2). deref copy_of_p(2). ~PrT(copy_of_p(2)). i now: 2, p(3)
~PrT(p(3)).
  • Le premier cas, *++p, est simple : incrémenter, déréférencer, c'est tout.
  • Dans le deuxième cas, ++*p, l'incrémentation est l'opérateur intégré d'incrémentation d'entier, appliqué au résultat du déréférencement, une référence à un int, et non à la classe (notez qu'il n'y a pas de sortie d'opérateur d'incrémentation) ! Mais parce que la référence pointe vers le membre de classe, le même effet est obtenu : p.val est incrémenté, comme le montre p(2).
  • Le troisième cas, *p++, est le plus intéressant. Comme c'est d'usage, la fonction de l'opérateur incrémente internement l'objet original mais retourne une copie avec la valeur non incrémentée. Cette copie est déréférencée, renvoyant la val non incrémentée, puis détruite. Cependant, l'original p a une valeur de 3 après l'impression et, à la fin, est détruit également.

-1voto

Kiran Padwal Points 107

Postfix et préfixe ont une plus haute priorité que la déréférence donc

*ptr++ ici post-incrémente ptr et pointe ensuite vers la nouvelle valeur de ptr

*++ptr ici pré-incrémente d'abord puis pointe vers la nouvelle valeur de ptr

++*ptr ici obtient d'abord la valeur pointée par ptr et incrémente cette valeur

-1voto

iammosespaulr Points 9
const char *p = "Bonjour";   

*p signifie "Bonjour"
          ^
          | 
          p

*p++ signifie "Bonjour"
             ^
             | 
             p

*++p signifie "Bonjour"
            ^
            |     (PENDANT QUE L'INSTRUCTION EST EXÉCUTÉE)
            p

*++p signifie "Bonjour"
             ^
             |     (APRÈS L'EXÉCUTION DE L'INSTRUCTION)
             p

++*p signifie que vous essayez d'incrémenter la valeur ASCII de *p qui

   est "Bonjour"
       ^
       | 
       p

vous ne pouvez pas incrémenter la valeur car c'est une constante donc vous obtiendriez une erreur

quant à votre boucle while, la boucle s'exécute jusqu'à ce que *p++ atteigne la fin de la chaîne où il y a un caractère '\0' (NULL).

Maintenant, puisque *p++ saute le premier caractère, vous n'obtiendriez votre sortie qu'à partir du deuxième caractère.

Le code suivant ne produira rien car la boucle while a '\0'

const char *p = "Bonjour";
    while('\0') 
         printf("%c",*p);

Le code suivant vous donnera la même sortie que le code suivant c'est-à-dire ello.

const char *p = "Bonjour";
    while(*++p)
         printf("%c",*p);

...................................

const char *p = "Bonjour";
    while(*p++)
         printf("%c",*p);

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