Come confrontare i puntatori?


88

Supponiamo che io abbia 2 puntatori:

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

Se voglio confrontarli e vedere se puntano nello stesso punto, (a == b) funziona?


6
I puntatori di confronto IIRC non sono definiti, a meno che non puntino a elementi all'interno dello stesso array
vedere il

1
@sehe Hey, la tua risposta qui sotto cancella questo vecchio commento.
Spencer

Risposte:


72

Sì, questa è la definizione di uguaglianza del puntatore: entrambi puntano alla stessa posizione (o sono alias del puntatore )


2
Il puntatore è (in parole povere) essenzialmente un valore intero per l'indirizzo di memoria nel tuo computer. È come confrontare i numeri interi.
Kemin Zhou

6
@KeminZhou: questo è vero sulla maggior parte dei computer attuali, ma falso in generale. Anche sul vecchio PC AT 8086 del 1980 era falso
Basile Starynkevitch

110

Per un po 'di fatti ecco il testo pertinente dalle specifiche

Operatore di uguaglianza (==,! =)

I puntatori a oggetti dello stesso tipo possono essere confrontati per l'uguaglianza con i risultati attesi "intuitivi":

Dal § 5.10 dello standard C ++ 11:

I puntatori dello stesso tipo (dopo le conversioni del puntatore) possono essere confrontati per l'uguaglianza. Due puntatori dello stesso tipo sono uguali se e solo se sono entrambi nulli, entrambi puntano alla stessa funzione o entrambi rappresentano lo stesso indirizzo ( 3.9.2 ).

(tralasciando i dettagli sul confronto dei puntatori al membro e / o le costanti del puntatore nullo - continuano lungo la stessa riga di 'Do What I Mean' :)

  • [...] Se entrambi gli operandi sono nulli, vengono confrontati uguali. Altrimenti, se solo uno è nullo, si confrontano disuguali. [...]

L'avvertenza più `` evidente '' ha a che fare con i virtuali, e sembra essere anche la cosa logica da aspettarsi:

  • [...] se uno dei due è un puntatore a una funzione membro virtuale, il risultato non è specificato. Altrimenti si confrontano uguali se e solo se si riferissero allo stesso membro dello stesso oggetto più derivato (1.8) o allo stesso sottooggetto se fossero dereferenziati con un oggetto ipotetico del tipo di classe associato. [...]

Operatori relazionali (<,>, <=,> =)

Dal § 5.9 dello standard C ++ 11:

I puntatori a oggetti o funzioni dello stesso tipo (dopo le conversioni del puntatore) possono essere confrontati, con un risultato definito come segue:

  1. Se due puntatori peq dello stesso tipo puntano allo stesso oggetto o funzione, o entrambi puntano uno oltre la fine dello stesso array, o sono entrambi nulli, allora p<=qe p>=qentrambi restituiscono vero e p<qed p>qentrambi restituiscono falso.
  2. Se due puntatori peq dello stesso tipo puntano a oggetti diversi che non sono membri dello stesso oggetto o elementi dello stesso array oa funzioni diverse, o se solo uno di essi è nullo, i risultati di p<q, p>q, p<=q,e p>=q non sono specificati .
  3. Se due puntatori puntano a membri di dati non statici dello stesso oggetto, o a suboggetti o elementi di matrice di tali membri, ricorsivamente, il puntatore al membro dichiarato più tardi confronta maggiore a condizione che i due membri abbiano lo stesso controllo di accesso (clausola 11) e purché la loro classe non sia un sindacato.
  4. Se due puntatori puntano a membri di dati non statici dello stesso oggetto con un diverso controllo di accesso (clausola 11), il risultato non è specificato.
  5. Se due puntatori puntano a membri dati non statici dello stesso oggetto unione, vengono confrontati uguali (dopo la conversione a void*, se necessario). Se due puntatori puntano a elementi della stessa matrice o uno oltre la fine della matrice, il puntatore all'oggetto con il pedice più alto confronta più alto.
  6. Altri confronti di puntatori non sono specificati.

Quindi, se avessi:

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

Anche OK:

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

Ma dipende dalla somethingtua domanda:

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: cos'altro c'è nella libreria standard?

§ 20.8.5 / 8 : "Per i modelli greater, less, greater_equal, e less_equal, le specializzazioni per qualsiasi tipo di puntatore producono un ordine totale, anche se il built-in operatori <, >, <=, >=non lo fanno."

Quindi, puoi ordinare globalmente qualsiasi dispari void*fintanto che usi std::less<>e amici, non nudo operator<.


La int *a = arr;linea trarrebbe vantaggio dall'inclusione di un riferimento a stackoverflow.com/questions/8412694/address-of-array ? Non sono sicuro che sia abbastanza rilevante per la domanda posta però ...
nonsensickle

Oggi, l'inimitabile @JerryCoffin mi ha reso consapevole del fatto che la libreria standard ha specifiche più rigorose per i modelli di oggetti funzione definiti in <functional>. Aggiunto.
guarda il

Sembra che questo capitolo sia cambiato nella bozza C ++ in corso. A meno che io non lo capisca
SomeWittyUsername


25

L' ==operatore sui puntatori confronterà il loro indirizzo numerico e quindi determinerà se puntano allo stesso oggetto.


12
È un po 'più complicato se è coinvolta l'ereditarietà multipla.
fredoverflow

17

Per riassumere. Se vogliamo vedere se due puntatori puntano alla stessa posizione di memoria, possiamo farlo. Inoltre se vogliamo confrontare il contenuto della memoria puntato da due puntatori possiamo farlo anche noi, ricordiamoci solo di dereferenziarli prima.

Se abbiamo

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

che sono due puntatori dello stesso tipo possiamo:

Confronta indirizzo di memoria:

a==b

e confronta i contenuti:

*a==*b

1

Codice semplice per controllare l'alias del puntatore:

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

Produzione:

p1 and p2 alias each other
p3 and p4 do not alias each other

1

Il confronto dei puntatori non è portabile, ad esempio in DOS diversi valori dei puntatori puntano alla stessa posizione, il confronto dei puntatori restituisce 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}--------------------------------------------------*/

Compilalo sotto Borland C 5.0, ecco il risultato:

/*--{++: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}--------------------------------------------------*/
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.