¿Cómo comparar punteros?

88

Supongamos que tengo 2 punteros:

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

Si quiero compararlos y ver si apuntan al mismo lugar, ¿funciona (a == b)?

Joey Franklin
fuente
6
Los punteros de comparación de IIRC no están definidos, a menos que apunten a elementos dentro de la misma matriz
consulte el
1
@sehe Oye, tu respuesta a continuación cancela este comentario anterior.
Spencer

Respuestas:

72

Sí, esa es la definición de igualdad de puntero: ambos apuntan a la misma ubicación (o son alias de puntero )

Basile Starynkevitch
fuente
2
El puntero es (en términos simples) esencialmente un valor entero para la dirección de memoria en su computadora. Es como comparar enteros.
Kemin Zhou
5
@KeminZhou: esto es cierto en la mayoría de las computadoras actuales, pero falso en general. Incluso en el antiguo PC AT 8086 de 1980 era falso
Basile Starynkevitch
109

Para algunos hechos, aquí está el texto relevante de las especificaciones.

Operador de igualdad (==,! =)

Los punteros a objetos del mismo tipo se pueden comparar por igualdad con los resultados esperados 'intuitivos':

Del § 5.10 del estándar C ++ 11:

Los punteros del mismo tipo (después de las conversiones de punteros) se pueden comparar para determinar la igualdad. Dos punteros del mismo tipo se comparan igual si y solo si ambos son nulos, ambos apuntan a la misma función o ambos representan la misma dirección ( 3.9.2 ).

(dejando de lado los detalles sobre la comparación de punteros al miembro yo las constantes de puntero nulo; continúan en la misma línea de 'Do What I Mean' :)

  • [...] Si ambos operandos son nulos, se comparan igual. De lo contrario, si solo uno es nulo, se comparan desiguales. [...]

La advertencia más 'conspicua' tiene que ver con los virtuales, y también parece ser lo lógico:

  • [...] si alguno es un puntero a una función miembro virtual, el resultado no está especificado. De lo contrario, se comparan igual si y solo si se referirían al mismo miembro del mismo objeto más derivado (1.8) o al mismo subobjeto si fueran desreferenciados con un objeto hipotético del tipo de clase asociado. [...]

Operadores relacionales (<,>, <=,> =)

Del § 5.9 del estándar C ++ 11:

Los punteros a objetos o funciones del mismo tipo (después de las conversiones de punteros) se pueden comparar, con un resultado definido de la siguiente manera:

  1. Si dos punteros pyq del mismo tipo apuntan al mismo objeto o función, o ambos apuntan uno más allá del final de la misma matriz, o ambos son nulos, entonces p<=qy p>=qambos dan como resultado verdadero p<qy p>qambos dan como resultado falso.
  2. Si dos punteros pyq del mismo tipo apuntan a diferentes objetos que no son miembros del mismo objeto o elementos de la misma matriz o funciones diferentes, o si solo uno de ellos es nulo, los resultados de p<q, p>q, p<=q,y p>=q no están especificados .
  3. Si dos punteros apuntan a miembros de datos no estáticos del mismo objeto, o a subobjetos o elementos de matriz de dichos miembros, de forma recursiva, el puntero al miembro declarado más tarde se compara mayor siempre que los dos miembros tengan el mismo control de acceso (Cláusula 11) y siempre que su clase no sea un sindicato.
  4. Si dos punteros apuntan a miembros de datos no estáticos del mismo objeto con diferente control de acceso (cláusula 11), el resultado no se especifica.
  5. Si dos punteros apuntan a miembros de datos no estáticos del mismo objeto de unión, se comparan igual (después de la conversión a void*, si es necesario). Si dos punteros apuntan a elementos de la misma matriz o uno más allá del final de la matriz, el puntero al objeto con el subíndice más alto compara más alto.
  6. Otras comparaciones de punteros no están especificadas.

Entonces, si tuvieras:

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

También está bien:

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

Pero depende del somethingen su pregunta:

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
}

Bono: ¿qué más hay en la biblioteca estándar?

§ 20.8.5 / 8 : "Para las plantillas greater, less, greater_equal, y less_equal, las especializaciones para cualquier tipo de puntero producen un orden total, incluso si el incorporado en los operadores <, >, <=, >=no lo hacen."

Por lo tanto, puede ordenar globalmente cualquier impar void*siempre que use std::less<>y amigos, no solo operator<.

sehe
fuente
¿Se int *a = arr;beneficiaría la línea de incluir una referencia a stackoverflow.com/questions/8412694/address-of-array ? Sin embargo, no estoy seguro de si es lo suficientemente relevante para la pregunta formulada ...
sin sentido
Hoy, el inimitable @JerryCoffin me hizo consciente del hecho de que la biblioteca estándar tiene especificaciones más estrictas para las plantillas de objetos de función definidas en <functional>. Adicional.
sehe
Parece que este capítulo ha cambiado en el borrador de C ++ en curso. A menos que lo entienda mal, no hay más comportamiento no especificado: open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf
SomeWittyUsername
@SomeWittyUsername seguía siendo cierto en C ++ 14 al menos
Lightness Races in Orbit
25

El ==operador de punteros comparará su dirección numérica y, por lo tanto, determinará si apuntan al mismo objeto.

JaredPar
fuente
12
Es un poco más complicado si se trata de una herencia múltiple.
fredoverflow
17

Para resumir. Si queremos ver si dos punteros apuntan a la misma ubicación de memoria, podemos hacerlo. Además, si queremos comparar el contenido de la memoria apuntada por dos punteros, también podemos hacerlo, solo recuerde desreferenciarlos primero.

Si tenemos

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

que son dos punteros del mismo tipo podemos:

Comparar dirección de memoria:

a==b

y comparar contenidos:

*a==*b
ldgorman
fuente
1

Código simple para verificar el alias del puntero:

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

Salida:

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

Comparar punteros no es portátil, por ejemplo, en DOS, diferentes valores de puntero apuntan a la misma ubicación, la comparación de punteros devuelve falso.

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

Compílelo bajo Borland C 5.0, aquí está el resultado:

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