Как сравнить указатели?

Предположим, у меня есть 2 указателя:

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

Если я хочу сравнить их и посмотреть, указывают ли они на одно и то же место, работает (a == b)?

8 ответов

Решение

Да, это определение равенства указателей: оба они указывают на одно и то же местоположение (или являются псевдонимами указателей)

Для небольшого количества фактов вот соответствующий текст из спецификаций

Оператор равенства (==,!=)

Указатели на объекты одного типа можно сравнить на равенство с "интуитивными" ожидаемыми результатами:

Из § 5.10 стандарта C++11:

Указатели одного типа (после преобразования указателей) можно сравнивать на равенство. Два указателя одного типа сравниваются равными, если и только если они оба равны нулю, оба указывают на одну и ту же функцию или оба представляют один и тот же адрес (3.9.2).

(опуская детали сравнения указателей на член и / или константы нулевого указателя - они продолжают в той же строке "Делай, что я имею в виду":)

  • [...] Если оба операнда равны нулю, они сравниваются одинаково. В противном случае, если только один равен нулю, они сравниваются неравно.[...]

Самое "бросающееся в глаза" предостережение связано с виртуальными машинами, и, кажется, вполне логично ожидать этого:

  • [...] если любой из них является указателем на виртуальную функцию-член, результат не указан. В противном случае они сравниваются равными, если и только если они ссылались бы на один и тот же член того же самого производного объекта (1.8) или того же подобъекта, если на них была разыменована гипотетический объект связанного типа класса.[...]

Реляционные операторы (<,>, <=,> =)

Из п. 5.9 стандарта C++11:

Указатели на объекты или функции одного и того же типа (после преобразования указателей) можно сравнить с результатом, определяемым следующим образом:

  1. Если два указателя p и q одного и того же типа указывают на один и тот же объект или функцию, или оба указывают один за концом одного и того же массива, или оба равны нулю, то p<=q а также p>=q оба дают истину и p<q а также p>q оба дают ложь.
  2. Если два указателя p и q одного и того же типа указывают на разные объекты, которые не являются членами одного и того же объекта или элементов одного и того же массива или на разные функции, или если только один из них имеет значение null, результаты p<q,p>q,p<=q, а также p>=q не определены.
  3. Если два указателя указывают на нестатические элементы данных одного и того же объекта или субобъекты или элементы массива таких элементов, рекурсивно, указатель на объявленный позже элемент сравнивается больше, если два элемента имеют одинаковый контроль доступа (раздел 11) и при условии, что их класс не является союзом.
  4. Если два указателя указывают на нестатические элементы данных одного и того же объекта с разным контролем доступа (пункт 11), результат не уточняется.
  5. Если два указателя указывают на нестатические элементы данных одного и того же объекта объединения, они сравниваются равными (после преобразования в void*, если необходимо). Если два указателя указывают на элементы одного и того же массива или один за концом массива, указатель на объект с более высоким индексом сравнивается выше.
  6. Другие сравнения указателей не определены.

Итак, если у вас было:

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

Также хорошо:

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

Но это зависит от something в вашем вопросе:

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
}

Бонус: что еще есть в стандартной библиотеке?

§ 20.8.5 / 8: "Для шаблонов greater, less, greater_equal, а также less_equal, специализации для любого типа указателя дают общий порядок, даже если встроенные операторы <, >, <=, >= не делайте."

Таким образом, вы можете глобально заказать любой нечетный void* пока вы используете std::less<> а друзья не голые operator<,

== оператор по указателям сравнивает их числовой адрес и, следовательно, определяет, указывают ли они на один и тот же объект.

Подводить итоги. Если мы хотим увидеть, указывают ли два указателя на одну и ту же область памяти, мы можем это сделать. Также, если мы хотим сравнить содержимое памяти, на которое указывают два указателя, мы тоже можем это сделать, просто помните, чтобы сначала разыменовать их.

Если у нас есть

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

которые являются двумя указателями одного типа, мы можем:

Сравните адрес памяти:

a==b

и сравните содержание:

*a==*b

Это зависит от типов значений и способа определения операторов. Например, сравнение строк выполняется по значению, а не по адресу. Но char * обычно по адресу (я думаю).

Большая ловушка для неосторожных. Нет гарантированного оператора сравнения указателей, но

        (void *)a == (void *)b 

вероятно, достаточно безопасно.

Сравнение указателей не переносимо, например, в DOS разные значения указателей указывают на одно и то же место, сравнение указателей возвращает 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}--------------------------------------------------*/

Скомпилируйте его под Borland C 5.0, вот результат:

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

Простой код для проверки псевдонимов указателей:

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

Выход:

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

Допустим, вы должны указатели:

int *a = something1;
int *b = something2;

Вы знаете адрес что-то1, которое является & что-то1. Также адрес что-то2 - это & ​​что-то2.

Итак, вам нужно проверить, правильны ли два адреса, на которые указывают указатели.

так что вы используете что-то вроде

if(&something1 == &something2) {
//do something
}

или вы можете использовать оператор ==, чтобы проверить, имеет ли указатель a равное значение с указателем b.

Другие вопросы по тегам