Como comparar ponteiros?

88

Suponha que eu tenha 2 ponteiros:

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

Se eu quiser compará-los e ver se eles apontam para o mesmo lugar, (a == b) funciona?

Joey Franklin
fonte
6
A comparação de ponteiros do IIRC é indefinida, a menos que eles apontem para elementos dentro da mesma matriz
ver
1
@sehe Ei, sua resposta abaixo cancela este comentário antigo.
Spencer

Respostas:

72

Sim, essa é a definição de igualdade de ponteiro: ambos apontam para o mesmo local (ou são apelidos de ponteiro )

Basile Starynkevitch
fonte
2
Ponteiro é (em termos leigos) essencialmente um valor inteiro para o endereço de memória em seu computador. É como comparar inteiros.
Kemin Zhou
5
@KeminZhou: isso é verdadeiro na maioria dos computadores atuais, mas falso em geral. Mesmo no antigo PC AT 8086 de 1980, era falso
Basile Starynkevitch
109

Para alguns fatos, aqui está o texto relevante das especificações

Operador de igualdade (==,! =)

Ponteiros para objetos do mesmo tipo podem ser comparados por igualdade com os resultados esperados 'intuitivos':

De § 5.10 do padrão C ++ 11:

Ponteiros do mesmo tipo (após conversões de ponteiro) podem ser comparados quanto à igualdade. Dois ponteiros do mesmo tipo são comparados iguais se e somente se forem nulos, ambos apontam para a mesma função ou representam o mesmo endereço ( 3.9.2 ).

(omitindo detalhes sobre a comparação de ponteiros para membros e / ou constantes de ponteiros nulos - eles continuam na mesma linha de 'Faça o que quero dizer' :)

  • [...] Se ambos os operandos são nulos, eles comparam iguais. Caso contrário, se apenas um for nulo, eles comparam desiguais. [...]

A advertência mais 'conspícua' tem a ver com os virtuais e também parece ser a coisa lógica a se esperar:

  • [...] se qualquer um deles for um ponteiro para uma função de membro virtual, o resultado não é especificado. Caso contrário, eles são comparados igual se e somente se eles se referissem ao mesmo membro do mesmo objeto mais derivado (1.8) ou ao mesmo subobjeto se eles fossem referenciados com um objeto hipotético do tipo de classe associado. [...]

Operadores relacionais (<,>, <=,> =)

De § 5.9 do padrão C ++ 11:

Ponteiros para objetos ou funções do mesmo tipo (após conversões de ponteiro) podem ser comparados, com um resultado definido da seguinte maneira:

  1. Se dois ponteiros p e q do mesmo tipo apontam para o mesmo objeto ou função, ou ambos apontam um após o final do mesmo array, ou são ambos nulos, então p<=qe p>=qambos resultam em verdadeiro e p<qe p>qambos resultam em falso.
  2. Se dois ponteiros p e q do mesmo tipo apontam para objetos diferentes que não são membros do mesmo objeto ou elementos do mesmo array ou para funções diferentes, ou se apenas um deles é nulo, os resultados de p<q, p>q, p<=q,e p>=q não são especificados .
  3. Se dois ponteiros apontam para membros de dados não estáticos do mesmo objeto, ou para subobjetos ou elementos de matriz de tais membros, recursivamente, o ponteiro para o último membro declarado compara maior, desde que os dois membros tenham o mesmo controle de acesso (Cláusula 11) e desde que sua classe não seja um sindicato.
  4. Se dois ponteiros apontarem para membros de dados não estáticos do mesmo objeto com controle de acesso diferente (Cláusula 11), o resultado não será especificado.
  5. Se dois ponteiros apontarem para membros de dados não estáticos do mesmo objeto de união, eles serão comparados da mesma forma (após a conversão para void*, se necessário). Se dois ponteiros apontam para elementos da mesma matriz ou um além do final da matriz, o ponteiro para o objeto com o subscrito mais alto é comparado mais alto.
  6. Outras comparações de ponteiro não são especificadas.

Então, se você tivesse:

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

Também ok:

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

Mas depende do somethingem sua pergunta:

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
}

Bônus: o que mais há na biblioteca padrão?

§ 20.8.5 / 8 : "Para modelos greater, less, greater_equal, e less_equal, os especializações para qualquer tipo de ponteiro produzir uma ordem total, mesmo se o embutido operadores <, >, <=, >=não fazer."

Portanto, você pode solicitar globalmente qualquer item ímpar void*, desde que use std::less<>e amigos, não vazio operator<.

ver
fonte
A int *a = arr;linha se beneficiaria com a inclusão de uma referência a stackoverflow.com/questions/8412694/address-of-array ? Não tenho certeza se é relevante o suficiente para a pergunta feita ...
sem sentido
Hoje, o inimitável @JerryCoffin me alertou para o fato de que a biblioteca padrão possui especificações mais rigorosas para os modelos de objeto de função definidos em <functional>. Adicionado.
ver
Parece que este capítulo mudou no rascunho C ++ em andamento. A menos que eu não entenda
SomeWittyUsername
@SomeWittyUsername ainda era verdadeiro em C ++ 14, pelo menos
Lightness Races in Orbit
25

O ==operador em ponteiros irá comparar seu endereço numérico e, portanto, determinar se eles apontam para o mesmo objeto.

JaredPar
fonte
12
É um pouco mais complicado se a herança múltipla estiver envolvida.
fredoverflow
17

Resumindo. Se quisermos ver se dois ponteiros apontam para a mesma localização da memória, podemos fazer isso. Além disso, se quisermos comparar o conteúdo da memória apontado por dois ponteiros, também podemos fazer isso, apenas lembre-se de desreferenciá-los primeiro.

Se tiver-mos

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

que são dois indicadores do mesmo tipo, podemos:

Compare o endereço de memória:

a==b

e compare os conteúdos:

*a==*b
ldgorman
fonte
1

Código simples para verificar o alias do ponteiro:

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

Resultado:

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

Comparar ponteiros não é portátil, por exemplo, no DOS, diferentes valores de ponteiro apontam para o mesmo local, a comparação dos ponteiros retorna 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}--------------------------------------------------*/

Compile-o no Borland C 5.0, aqui está o 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
fonte