How do you check if two pointers point to the same object?
Asked Answered
H

7

105

Suppose I have 2 pointers:

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

If I want to compare them and see if they point at the same object, does a == b work?

Hog answered 31/1, 2012 at 20:22 Comment(0)
G
79

Yes, that is the definition of raw pointer equality: they both point to the same location (or are pointer aliases); usually in the virtual address space of the process running your application coded in C++ and managed by some operating system (but C++ can also be used for programming embedded devices with micro-controllers having a Harward architecture: on such microcontrollers some pointer casts are forbidden and makes no sense - since read only data could sit in code ROM)

For C++, read a good C++ programming book, see this C++ reference website, read the documentation of your C++ compiler (perhaps GCC or Clang) and consider coding with smart pointers. Maybe read also some draft C++ standard, like n4713 or buy the official standard from your ISO representative.

The concepts and terminology of garbage collection are also relevant when managing pointers and memory zones obtained by dynamic allocation (e.g. ::operator new), so read perhaps the GC handbook.

For pointers on Linux machines, see also this.

Gatekeeper answered 31/1, 2012 at 20:23 Comment(3)
Pointer is (in layman's term) essentially a integer value for the memory address in your computer. It is like comparing integers.Joettejoey
@KeminZhou: this is true on most current computers, but false in general. Even on the old 1980 PC AT 8086 it was falseGatekeeper
Absolutely NOT. In C++ operators are just arbitrary functions that can do what they please. In particular, for strings == is a value comparison, not a string comparison. For iterating through a stream it does very odd things. This is a big trap for the unwary. If you want to compare pointers, you need to cast to something.Mouthful
T
128

For a bit of facts here is the relevant text from the specifications

Equality operator (==,!=)

Pointers to objects of the same type can be compared for equality with the 'intuitive' expected results:

From § 5.10 of the C++11 standard:

Pointers of the same type (after pointer conversions) can be compared for equality. Two pointers of the same type compare equal if and only if they are both null, both point to the same function, or both represent the same address (3.9.2).

(leaving out details on comparison of pointers to member and or the null pointer constants - they continue down the same line of 'Do What I Mean':)

  • [...] If both operands are null, they compare equal. Otherwise if only one is null, they compare unequal.[...]

The most 'conspicuous' caveat has to do with virtuals, and it does seem to be the logical thing to expect too:

  • [...] if either is a pointer to a virtual member function, the result is unspecified. Otherwise they compare equal if and only if they would refer to the same member of the same most derived object (1.8) or the same subobject if they were dereferenced with a hypothetical object of the associated class type. [...]

Relational operators (<,>,<=,>=)

From § 5.9 of the C++11 standard:

Pointers to objects or functions of the same type (after pointer conversions) can be compared, with a result defined as follows:

  1. If two pointers p and q of the same type point to the same object or function, or both point one past the end of the same array, or are both null, then p<=q and p>=q both yield true and p<q and p>q both yield false.
  2. If two pointers p and q of the same type point to different objects that are not members of the same object or elements of the same array or to different functions, or if only one of them is null, the results of p<q, p>q, p<=q, and p>=q are unspecified.
  3. If two pointers point to non-static data members of the same object, or to subobjects or array elements of such members, recursively, the pointer to the later declared member compares greater provided the two members have the same access control (Clause 11) and provided their class is not a union.
  4. If two pointers point to non-static data members of the same object with different access control (Clause 11) the result is unspecified.
  5. If two pointers point to non-static data members of the same union object, they compare equal (after conversion to void*, if necessary). If two pointers point to elements of the same array or one beyond the end of the array, the pointer to the object with the higher subscript compares higher.
  6. Other pointer comparisons are unspecified.

So, if you had:

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

Also OK:

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

But it depends on the something in your question:

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
}

Bonus: what else is there in the standard library?

§ 20.8.5/8: "For templates greater, less, greater_equal, and less_equal, the specializations for any pointer type yield a total order, even if the built-in operators <, >, <=, >= do not."

So, you can globally order any odd void* as long as you use std::less<> and friends, not bare operator<.

Tawnytawnya answered 31/1, 2012 at 20:47 Comment(6)
Would the int *a = arr; line benefit from including a reference to https://mcmap.net/q/23069/-why-is-the-address-of-an-array-the-same-the-array-converted-to-a-pointer? I'm not sure if it is relevant enough to the question asked though...Sayce
Today, the inimitable @JerryCoffin made me aware of the fact that the standard library has more stringent specifications for the function object templates defined in <functional>. Added.Tawnytawnya
It seems that this chapter has changed in the ongoing C++ draft. Unless I misunderstand it, there is no more unspecified behavior: open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdfRosio
@Rosio Was still true in C++14 at leastEpiphyte
Wrong. "a" + "b" == "ab" is probably true, value comparson for strings. Operators do what they want. This is a big trap for the unwary. There is no safe ptr operation. And for streams == is particularly weird.Mouthful
@Turntable I think you might have posted your comment somewhere you didn't intend?Tawnytawnya
G
79

Yes, that is the definition of raw pointer equality: they both point to the same location (or are pointer aliases); usually in the virtual address space of the process running your application coded in C++ and managed by some operating system (but C++ can also be used for programming embedded devices with micro-controllers having a Harward architecture: on such microcontrollers some pointer casts are forbidden and makes no sense - since read only data could sit in code ROM)

For C++, read a good C++ programming book, see this C++ reference website, read the documentation of your C++ compiler (perhaps GCC or Clang) and consider coding with smart pointers. Maybe read also some draft C++ standard, like n4713 or buy the official standard from your ISO representative.

The concepts and terminology of garbage collection are also relevant when managing pointers and memory zones obtained by dynamic allocation (e.g. ::operator new), so read perhaps the GC handbook.

For pointers on Linux machines, see also this.

Gatekeeper answered 31/1, 2012 at 20:23 Comment(3)
Pointer is (in layman's term) essentially a integer value for the memory address in your computer. It is like comparing integers.Joettejoey
@KeminZhou: this is true on most current computers, but false in general. Even on the old 1980 PC AT 8086 it was falseGatekeeper
Absolutely NOT. In C++ operators are just arbitrary functions that can do what they please. In particular, for strings == is a value comparison, not a string comparison. For iterating through a stream it does very odd things. This is a big trap for the unwary. If you want to compare pointers, you need to cast to something.Mouthful
M
25

The == operator on pointers will compare their numeric address and hence determine if they point to the same object.

Myriammyriameter answered 31/1, 2012 at 20:24 Comment(1)
It's a little more complicated if multiple inheritance is involved.Valeriavalerian
H
23

To sum up. If we want to see if two pointers point to the same memory location we can do that. Also if we want to compare the contents of the memory pointed to by two pointers we can do that too, just remeber to dereference them first.

If we have

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

which are two pointers of the same type we can:

Compare memory address:

a==b

and compare contents:

*a==*b
Hawthorne answered 1/2, 2012 at 16:32 Comment(0)
P
3

Comparing pointers is not portable, for example in DOS different pointer values points to the same location, comparison of the pointers returns 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}--------------------------------------------------*/

Compile it under Borland C 5.0, here is the result:

/*--{++: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}--------------------------------------------------*/
Photosensitive answered 8/10, 2020 at 12:18 Comment(2)
In end of 2020 or 2021, it is time to switch to better compilers like GCCGatekeeper
@BasileStarynkevitch: In both clang and gcc, equality comparison between a pointer to one object and a pointer just past the end of an object that happens to immediately precede it in the address space--a scenario expressly addressed by the Standard--is prone to behave in a fashion which is consistent neither with the comparison yielding true nor with it comparing false.Terri
M
3

It depends on the types of the values, and the way that operators happen to have been defined. For example, string comparison is by value, not by address. But char * is by address normally (I think).

A big trap for the unwary. There is no guaranteed pointer comparison operator, but

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

is probably fairly safe.

Mouthful answered 25/1, 2021 at 8:22 Comment(0)
D
1

Simple code to check pointer aliasing:

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

Output:

p1 and p2 alias each other
p3 and p4 do not alias each other
Dodger answered 21/12, 2018 at 3:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.