Wie vergleiche ich Zeiger?

87

Angenommen, ich habe 2 Zeiger:

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

Wenn ich sie vergleichen und sehen möchte, ob sie auf dieselbe Stelle zeigen, funktioniert (a == b) dann?

Joey Franklin
quelle
6
IIRC Vergleich Zeiger ist undefiniert, es sei denn, sie zeigen auf Elemente innerhalb des gleichen Arrays
siehe
1
@sehe Hey, deine Antwort unten löscht diesen alten Kommentar.
Spencer

Antworten:

71

Ja, das ist die Definition der Zeigergleichheit: Beide zeigen auf dieselbe Position (oder sind Zeiger-Aliase ).

Basile Starynkevitch
quelle
1
Der Zeiger ist (im Sinne eines Laien) im Wesentlichen ein ganzzahliger Wert für die Speicheradresse in Ihrem Computer. Es ist wie ein Vergleich von ganzen Zahlen.
Kemin Zhou
5
@KeminZhou: Dies ist auf den meisten aktuellen Computern wahr, aber im Allgemeinen falsch. Sogar auf dem alten 1980 PC AT 8086 war es falsch
Basile Starynkevitch
108

Für ein paar Fakten hier der relevante Text aus den Spezifikationen

Gleichheitsoperator (== ,! =)

Zeiger auf Objekte des gleichen Typs können auf Gleichheit mit den "intuitiven" erwarteten Ergebnissen verglichen werden:

Aus § 5.10 des C ++ 11-Standards:

Zeiger des gleichen Typs (nach Zeigerkonvertierungen) können auf Gleichheit verglichen werden. Zwei Zeiger desselben Typs werden genau dann gleich verglichen, wenn beide null sind, beide auf dieselbe Funktion zeigen oder beide dieselbe Adresse darstellen ( 3.9.2 ).

(Details zum Vergleich der Zeiger mit dem Element und / oder den Nullzeigerkonstanten werden weggelassen - sie werden in derselben Zeile von 'Do What I Mean' fortgesetzt :)

  • [...] Wenn beide Operanden null sind, werden sie gleich verglichen. Andernfalls, wenn nur einer null ist, vergleichen sie ungleich. [...]

Die auffälligste Einschränkung hat mit Virtuals zu tun, und es scheint auch logisch zu sein, dies zu erwarten:

  • [...] Wenn einer der beiden Zeiger auf eine virtuelle Elementfunktion ist, ist das Ergebnis nicht angegeben. Andernfalls vergleichen sie genau dann gleich, wenn sie sich auf dasselbe Mitglied desselben am meisten abgeleiteten Objekts (1.8) oder auf dasselbe Unterobjekt beziehen würden, wenn sie mit einem hypothetischen Objekt des zugeordneten Klassentyps dereferenziert würden. [...]

Vergleichsoperatoren (<,>, <=,> =)

Aus § 5.9 des C ++ 11-Standards:

Zeiger auf Objekte oder Funktionen desselben Typs (nach Zeigerkonvertierungen) können verglichen werden. Das Ergebnis ist wie folgt definiert:

  1. Wenn zwei Zeiger p und q desselben Typ auf das gleiche Objekt oder die Funktion, oder beide eines Punktes hinter dem Ende des gleichen Array oder sind beide null, dann p<=qund p>=qsowohl Ausbeute als die tatsächliche p<qund p>qsowohl Ausbeute als falsch.
  2. Wenn zwei Zeiger p und q desselben Typs auf unterschiedliche Objekte verweisen, die nicht Mitglieder desselben Objekts oder auf Elemente desselben Arrays oder auf unterschiedliche Funktionen sind, oder wenn nur einer von ihnen null ist, sind die Ergebnisse von p<q, p>q, p<=q,und p>=q nicht angegeben .
  3. Wenn zwei Zeiger rekursiv auf nicht statische Datenelemente desselben Objekts oder auf Unterobjekte oder Array-Elemente solcher Elemente verweisen, ist der Zeiger auf das später deklarierte Element größer, vorausgesetzt, die beiden Elemente haben dieselbe Zugriffssteuerung (Abschnitt 11) und vorausgesetzt, ihre Klasse ist keine Gewerkschaft.
  4. Wenn zwei Zeiger auf nicht statische Datenelemente desselben Objekts mit unterschiedlicher Zugriffssteuerung verweisen (Abschnitt 11), ist das Ergebnis nicht angegeben.
  5. Wenn zwei Zeiger auf nicht statische Datenelemente desselben Vereinigungsobjekts verweisen, werden sie gleich verglichen (nach Konvertierung in void*, falls erforderlich). Wenn zwei Zeiger auf Elemente desselben Arrays oder einen hinter dem Ende des Arrays zeigen, wird der Zeiger auf das Objekt mit dem höheren Index höher verglichen.
  6. Andere Zeigervergleiche sind nicht spezifiziert.

Also, wenn Sie hätten:

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

Auch ok:

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

Aber es kommt darauf an, somethingin welcher Frage:

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: Was gibt es sonst noch in der Standardbibliothek?

§ 20.8.5 / 8 : „Für Vorlagen greater, less, greater_equal, und less_equalergeben die Spezialisierungen für jeden Zeigertyp einen Gesamtauftrag, auch wenn die integrierten Operatoren <, >, <=, >=dies nicht tun.“

So können Sie global jede ungerade bestellen,void* solange Sie std::less<>und Freunde verwenden, nicht nackt operator<.

sehe sehen
quelle
Würde die int *a = arr;Leitung von einem Verweis auf stackoverflow.com/questions/8412694/address-of-array profitieren ? Ich bin mir nicht sicher, ob es für die gestellte Frage relevant genug ist ...
unsinnig
Der unnachahmliche @ JerryCoffin hat mich heute darauf aufmerksam gemacht, dass die Standardbibliothek strengere Spezifikationen für die in definierten Funktionsobjektvorlagen enthält <functional>. Hinzugefügt.
sehe
Es scheint, dass sich dieses Kapitel im laufenden C ++ - Entwurf geändert hat. Sofern ich es nicht falsch verstehe
SomeWittyUsername
@SomeWittyUsername war zumindest in C ++ 14 noch wahr
Lightness Races in Orbit
25

Der ==Operator für Zeiger vergleicht seine numerische Adresse und bestimmt somit, ob sie auf dasselbe Objekt zeigen.

JaredPar
quelle
12
Es ist etwas komplizierter, wenn es sich um Mehrfachvererbung handelt.
Fredoverflow
17

Um zusammenzufassen. Wenn wir sehen wollen, ob zwei Zeiger auf denselben Speicherort zeigen, können wir das tun. Auch wenn wir den Inhalt des Speichers vergleichen möchten, auf den zwei Zeiger zeigen, können wir dies auch tun. Denken Sie nur daran, sie zuerst zu dereferenzieren.

Wenn wir haben

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

Das sind zwei Zeiger des gleichen Typs, die wir können:

Speicheradresse vergleichen:

a==b

und Inhalte vergleichen:

*a==*b
ldgorman
quelle
1

Einfacher Code zum Überprüfen des Zeiger-Aliasing:

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;
}

Ausgabe:

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

Das Vergleichen von Zeigern ist nicht portierbar. Beispielsweise zeigen unter DOS verschiedene Zeigerwerte auf dieselbe Position. Der Vergleich der Zeiger gibt false zurück.

/*--{++: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}--------------------------------------------------*/

Kompilieren Sie es unter Borland C 5.0, hier ist das Ergebnis:

/*--{++: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
quelle