Comment comparer des pointeurs?

88

Supposons que j'ai 2 pointeurs:

int *a = something;
int *b = something;

Si je veux les comparer et voir si elles pointent au même endroit, est-ce que (a == b) fonctionne?

Joey Franklin
la source
6
IIRC comparant des pointeurs est indéfini, à moins qu'ils pointent vers des éléments dans le même tableau
sehe
1
@sehe Hé, ta réponse ci-dessous annule cet ancien commentaire.
Spencer

Réponses:

72

Oui, c'est la définition de l'égalité des pointeurs: ils pointent tous les deux vers le même emplacement (ou sont des alias de pointeur )

Basile Starynkevitch
la source
2
Le pointeur est (en termes simples) essentiellement une valeur entière pour l'adresse mémoire de votre ordinateur. C'est comme comparer des entiers.
Kemin Zhou
5
@KeminZhou: c'est vrai sur la plupart des ordinateurs actuels, mais faux en général. Même sur l'ancien PC AT 8086 de 1980, c'était faux
Basile Starynkevitch
109

Pour un peu de faits, voici le texte pertinent du cahier des charges

Opérateur d'égalité (==,! =)

Les pointeurs vers des objets du même type peuvent être comparés pour l'égalité avec les résultats attendus `` intuitifs '':

À partir du § 5.10 de la norme C ++ 11:

Les pointeurs du même type (après les conversions de pointeurs) peuvent être comparés pour l'égalité. Deux pointeurs du même type se comparent égaux si et seulement s'ils sont tous deux nuls, tous deux pointent vers la même fonction, ou les deux représentent la même adresse ( 3.9.2 ).

(en laissant de côté les détails sur la comparaison des pointeurs vers le membre et / ou les constantes du pointeur nul - ils continuent sur la même ligne de 'Do What I Mean' :)

  • [...] Si les deux opérandes sont nuls, ils se comparent égaux. Sinon, si un seul est nul, ils comparent des inégalités. [...]

La mise en garde la plus `` visible '' concerne les virtuels, et cela semble être la chose logique à laquelle il faut également s'attendre:

  • [...] si l'un ou l'autre est un pointeur vers une fonction membre virtuelle, le résultat n'est pas spécifié. Sinon, ils se comparent égaux si et seulement s'ils font référence au même membre du même objet le plus dérivé (1.8) ou au même sous-objet s'ils ont été déréférencés avec un objet hypothétique du type de classe associé. [...]

Opérateurs relationnels (<,>, <=,> =)

À partir du § 5.9 de la norme C ++ 11:

Les pointeurs vers des objets ou des fonctions du même type (après conversions de pointeurs) peuvent être comparés, avec un résultat défini comme suit:

  1. Si deux pointeurs p et q du même type pointent vers le même objet ou la même fonction, ou tous les deux pointent un après la fin du même tableau, ou sont tous les deux nuls, alors p<=qet p>=qtous deux donnent vrai et p<qet p>qtous deux donnent faux.
  2. Si deux pointeurs p et q du même type pointent vers des objets différents qui ne sont pas membres du même objet ou des éléments du même tableau ou vers des fonctions différentes, ou si un seul d'entre eux est nul, les résultats de p<q, p>q, p<=q,et ne p>=q sont pas spécifiés .
  3. Si deux pointeurs pointent vers des membres de données non statiques du même objet, ou vers des sous-objets ou des éléments de tableau de ces membres, de manière récursive, le pointeur vers le membre déclaré plus tard est supérieur à condition que les deux membres aient le même contrôle d'accès (Article 11) et à condition que leur classe ne soit pas un syndicat.
  4. Si deux pointeurs pointent vers des membres de données non statiques du même objet avec un contrôle d'accès différent (Article 11), le résultat n'est pas spécifié.
  5. Si deux pointeurs pointent vers des membres de données non statiques du même objet union, ils se comparent égaux (après conversion en void*, si nécessaire). Si deux pointeurs pointent vers des éléments du même tableau ou un au-delà de la fin du tableau, le pointeur vers l'objet avec l'indice le plus élevé se compare plus haut.
  6. Les autres comparaisons de pointeurs ne sont pas spécifiées.

Donc, si vous aviez:

int arr[3];
int *a = arr;
int *b = a + 1;
assert(a != b); // OK! well defined

Aussi correct:

struct X { int x,y; } s;
int *a = &s.x;
int *b = &s.y;
assert(b > a); // OK! well defined

Mais cela dépend de la somethingquestion dans votre question:

int g; 
int main()
{
     int h;
     int i;

     int *a = &g;
     int *b = &h; // can't compare a <=> b
     int *c = &i; // can't compare b <=> c, or a <=> c etc.
     // but a==b, b!=c, a!=c etc. are supported just fine
}

Bonus: qu'y a-t-il d'autre dans la bibliothèque standard?

§ 20.8.5 / 8 : « Pour les modèles greater, less, greater_equalet less_equal, les spécialisations pour tout type de pointeur donnent un ordre total, même si le haut-opérateurs <, >, <=, >=ne le font pas. »

Ainsi, vous pouvez commander globalement n'importe quel impair void*tant que vous utilisez std::less<>et amis, pas nu operator<.

sehe
la source
La int *a = arr;ligne gagnerait-elle à inclure une référence à stackoverflow.com/questions/8412694/address-of-array ? Je ne sais pas si cela est suffisamment pertinent par rapport à la question posée ...
nonsensickle
Aujourd'hui, l'inimitable @JerryCoffin m'a fait prendre conscience du fait que la bibliothèque standard a des spécifications plus strictes pour les modèles d'objets de fonction définis dans <functional>. Ajoutée.
sehe le
Il semble que ce chapitre ait changé dans le projet C ++ en cours. Sauf erreur de ma compréhension, il n'y a plus de comportement indéterminé: open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf
SomeWittyUsername
@SomeWittyUsername était toujours vrai en C ++ 14 au moins
Courses de légèreté en orbite le
25

L' ==opérateur sur les pointeurs comparera leur adresse numérique et déterminera donc s'ils pointent vers le même objet.

JaredPar
la source
12
C'est un peu plus compliqué si l'héritage multiple est impliqué.
fredoverflow
17

Pour résumer. Si nous voulons voir si deux pointeurs pointent vers le même emplacement mémoire, nous pouvons le faire. Aussi, si nous voulons comparer le contenu de la mémoire pointé par deux pointeurs, nous pouvons le faire aussi, n'oubliez pas de les déréférencer en premier.

Si nous avons

int *a = something; 
int *b = something;

qui sont deux pointeurs du même type, nous pouvons:

Comparer l'adresse mémoire:

a==b

et comparez les contenus:

*a==*b
ldgorman
la source
1

Code simple pour vérifier l'alias du pointeur:

int main () {
    int a = 10, b = 20;
    int *p1, *p2, *p3, *p4;

    p1 = &a;
    p2 = &a;
    if(p1 == p2){
        std::cout<<"p1 and p2 alias each other"<<std::endl;
    }
    else{
        std::cout<<"p1 and p2 do not alias each other"<<std::endl;
    }
    //------------------------
    p3 = &a;
    p4 = &b;
    if(p3 == p4){
        std::cout<<"p3 and p4 alias each other"<<std::endl;
    }
    else{
        std::cout<<"p3 and p4 do not alias each other"<<std::endl;
    }
    return 0;
}

Production:

p1 and p2 alias each other
p3 and p4 do not alias each other
Pankaj Kumar Thapa
la source
1

La comparaison des pointeurs n'est pas portable, par exemple sous DOS différentes valeurs de pointeur pointent vers le même emplacement, la comparaison des pointeurs renvoie false.

/*--{++:main.c}--------------------------------------------------*/
#include <dos.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
  int   val_a = 123;
  int * ptr_0 = &val_a;
  int * ptr_1 = MK_FP(FP_SEG(&val_a) + 1, FP_OFF(&val_a) - 16);

  printf(" val_a = %d -> @%p\n", val_a, (void *)(&val_a));
  printf("*ptr_0 = %d -> @%p\n", *ptr_0, (void *)ptr_0);
  printf("*ptr_1 = %d -> @%p\n", *ptr_1, (void *)ptr_1);

  /* Check what returns the pointers comparison: */
  printf("&val_a == ptr_0 ====> %d\n", &val_a == ptr_0);
  printf("&val_a == ptr_1 ====> %d\n", &val_a == ptr_1);
  printf(" ptr_0 == ptr_1 ====> %d\n",  ptr_0 == ptr_1);

  printf("val_a = %d\n", val_a);

  printf(">> *ptr_0 += 100;\n");
             *ptr_0 += 100;

  printf("val_a = %d\n", val_a);

  printf(">> *ptr_1 += 500;\n");
             *ptr_1 += 500;

  printf("val_a = %d\n", val_a);

  return EXIT_SUCCESS;
}
/*--{--:main.c}--------------------------------------------------*/

Compilez-le sous Borland C 5.0, voici le résultat:

/*--{++:result}--------------------------------------------------*/
 val_a = 123 -> @167A:0FFE
*ptr_0 = 123 -> @167A:0FFE
*ptr_1 = 123 -> @167B:0FEE
&val_a == ptr_0 ====> 1
&val_a == ptr_1 ====> 0
 ptr_0 == ptr_1 ====> 0
val_a = 123
>> *ptr_0 += 100;
val_a = 223
>> *ptr_1 += 500;
val_a = 723
/*--{--:result}--------------------------------------------------*/
Maciej Labanowicz
la source