Как сравнить указатели?
Предположим, у меня есть 2 указателя:
int *a = something;
int *b = something;
Если я хочу сравнить их и посмотреть, указывают ли они на одно и то же место, работает (a == b)?
8 ответов
Да, это определение равенства указателей: оба они указывают на одно и то же местоположение (или являются псевдонимами указателей)
Для небольшого количества фактов вот соответствующий текст из спецификаций
Оператор равенства (==,!=)
Указатели на объекты одного типа можно сравнить на равенство с "интуитивными" ожидаемыми результатами:
Из § 5.10 стандарта C++11:
Указатели одного типа (после преобразования указателей) можно сравнивать на равенство. Два указателя одного типа сравниваются равными, если и только если они оба равны нулю, оба указывают на одну и ту же функцию или оба представляют один и тот же адрес (3.9.2).
(опуская детали сравнения указателей на член и / или константы нулевого указателя - они продолжают в той же строке "Делай, что я имею в виду":)
- [...] Если оба операнда равны нулю, они сравниваются одинаково. В противном случае, если только один равен нулю, они сравниваются неравно.[...]
Самое "бросающееся в глаза" предостережение связано с виртуальными машинами, и, кажется, вполне логично ожидать этого:
- [...] если любой из них является указателем на виртуальную функцию-член, результат не указан. В противном случае они сравниваются равными, если и только если они ссылались бы на один и тот же член того же самого производного объекта (1.8) или того же подобъекта, если на них была разыменована гипотетический объект связанного типа класса.[...]
Реляционные операторы (<,>, <=,> =)
Из п. 5.9 стандарта C++11:
Указатели на объекты или функции одного и того же типа (после преобразования указателей) можно сравнить с результатом, определяемым следующим образом:
- Если два указателя p и q одного и того же типа указывают на один и тот же объект или функцию, или оба указывают один за концом одного и того же массива, или оба равны нулю, то
p<=q
а такжеp>=q
оба дают истину иp<q
а такжеp>q
оба дают ложь.- Если два указателя p и q одного и того же типа указывают на разные объекты, которые не являются членами одного и того же объекта или элементов одного и того же массива или на разные функции, или если только один из них имеет значение null, результаты
p<q,
p>q,
p<=q,
а такжеp>=q
не определены.- Если два указателя указывают на нестатические элементы данных одного и того же объекта или субобъекты или элементы массива таких элементов, рекурсивно, указатель на объявленный позже элемент сравнивается больше, если два элемента имеют одинаковый контроль доступа (раздел 11) и при условии, что их класс не является союзом.
- Если два указателя указывают на нестатические элементы данных одного и того же объекта с разным контролем доступа (пункт 11), результат не уточняется.
- Если два указателя указывают на нестатические элементы данных одного и того же объекта объединения, они сравниваются равными (после преобразования в
void*
, если необходимо). Если два указателя указывают на элементы одного и того же массива или один за концом массива, указатель на объект с более высоким индексом сравнивается выше.- Другие сравнения указателей не определены.
Итак, если у вас было:
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.