如何比较指针?


88

假设我有2个指针:

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

如果我想比较它们,看看它们是否指向同一个地方,则(a == b)是否有效?


6
IIRC比较指针是不确定的,除非它们指向同一数组中的元素
2012年

1
@sehe嘿,您在下面的回答将取消此旧评论。
斯宾塞

Answers:


72

是的,这就是指针相等性的定义:它们都指向相同的位置(或者是指针别名


2
指针(用外行术语来说)本质上是计算机中内存地址的整数值。就像比较整数。
Kemin Zhou

5
@KeminZhou:在当前大多数计算机上都是如此,但通常是错误的。即使在1980年的旧PC AT 8086上,它也是错误的
Basile Starynkevitch

109

对于一点事实,这是规范中的相关文字

等于运算符(==,!=)

可以将指向相同类型对象的指针与“直观”预期结果进行相等性比较:

从 C ++ 11标准的5.10节开始

可以比较相同类型的指针(在指针转换之后)是否相等。当且仅当两个指针都为null,都指向相同的函数或都表示相同的地址(3.9.2)时,两个相同类型的指针才会相等。

(省略了有关比较指向成员和/或空指针常量的指针的详细信息-它们沿“执行我的意思”的同一行继续:)

  • [...]如果两个操作数都为null,则它们比较相等。否则,如果只有一个为空,则它们比较不相等。[...]

最“明显”的警告与虚拟机有关,这似乎也是合乎逻辑的事情:

  • [...]如果任何一个都是指向虚拟成员函数的指针,则结果不确定。否则,当且仅当它们被关联的类类型的假设对象取消引用时,它们将引用同一最派生对象(1.8)的同一成员或同一子对象时,它们的比较才相等。[...]

关系运算符(<,>,<=,> =)

根据C ++ 11标准的5.9节

可以比较指向相同类型的对象或函数的指针(在指针转换之后),其结果定义如下:

  1. 如果两个指针p和相同类型的指向相同的对象或功能或两者点一个过去的同一阵列的末端,的q或均为空,则p<=qp>=q两个产量真实p<qp>q两个假产率。
  2. 如果相同类型的两个指针p和q指向不同的对象,这些对象不是同一对象的成员,也不是同一数组的元素,或者指向不同的函数,或者如果其中只有一个为null,则p<q, p>q, p<=q,and 的结果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:“对于模板greaterlessgreater_equal,和less_equal,对于任何指针类型的专业化产生总订单,即使内置的运营商<><=>=没有。”

因此,您可以在全球范围内订购任何奇数void*(只要您使用std::less<>和朋友),而无需裸露operator<


int *a = arr;行从对stackoverflow.com/questions/8412694/address-of-array的引用中受益吗?我不确定它是否与所问的问题足够相关……
不客气

今天,无与伦比的@JerryCoffin让我意识到以下事实:标准库对中定义的函数对象模板具有更严格的规范<functional>。添加。
sehe 2014年

似乎在进行中的C ++草案中本章已更改。除非我误会了,否则不会出现其他未指定的行为:open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf
SomeWittyUsername 2015年



17

总结一下。如果要查看两个指针是否指向相同的内存位置,可以执行此操作。同样,如果我们想比较两个指针所指向的内存的内容,我们也可以这样做,只是要记住先取消引用它们。

如果我们有

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

我们可以使用两个相同类型的指针:

比较内存地址:

a==b

并比较内容:

*a==*b

1

检查指针别名的简单代码:

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

1

比较指针不是可移植的,例如在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}--------------------------------------------------*/
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.