2

I want to compare the memory address and pointer value of p, p + 1, q , and q + 1.

I want to understand, what the following values actually mean. I can't quite wrap my head around whats going on.

When I run the code:

  • I get an answer of 00EFF680 for everytime I compare the adresss p with another pointer.
  • I get an answer of 00EFF670 for everytime I compare the address of q with another pointer.
  • I get an answer of 15726208 when I look at the pointer value of p.
  • And I get an answer of 15726212 When I look at the pointer value of p + 1.

  • I get an answer of 15726192 when I look at the pointer value of q

  • And I get an answer of 15726200 Wehn I look at the pointer value of q + 1.

Code

#include <iostream>
#include <string>
using namespace std;
int main()
{
    int val = 20;
    double valD = 20;
    int *p = &val;
    double *q;
    q = &valD;
    cout << "Memory Address" << endl;
    cout << p == p + 1;
    cout << endl;
    cout << q == q + 1;
    cout << endl;
    cout << p == q;
    cout << endl;
    cout << q == p;
    cout << endl;
    cout << p == q + 1;
    cout << endl;
    cout << q == p + 1;
    cout << endl;
    cout << "Now Compare Pointer Value" << endl;
    cout << (unsigned long)(p) << endl;
    cout << (unsigned long) (p + 1) << endl;
    cout << (unsigned long)(q) << endl;
    cout << (unsigned long) (q + 1) << endl;
    cout <<"--------" << endl;
    return 0;
}
Ahmad Khan
  • 2,655
  • 19
  • 25

6 Answers6

2

There are a few warnings and/or errors.

The first is that overloaded operator << has higher precedence than the comparison operator (on clang++ -Woverloaded-shift-op-parentheses is the flag).

The second is that there is a comparison of distinct pointer types ('int *' and 'double *').

For the former, parentheses must be placed around the comparison to allow for the comparison to take precedence. For the latter, the pointers should be cast to a type that allows for safe comparison (e.g., size_t).

For instance on line 20, the following would work nicely.

cout << ((size_t) p == (size_t) (q + 1));

As for lines 25-28, this is standard pointer arithmetic. See the explanation here.

Community
  • 1
  • 1
Robert Prévost
  • 1,667
  • 16
  • 22
1

As to your question:

I want to compare p, p +1 , q , and q + 1. And Understand what the results mean.

If p is at address 0x80000000 then p+1 is at address 0x80000000 + sizeof(*p). If *p is int then this is 0x80000000 + 0x8 = 0x80000008. And the same reasoning applies for q.

So if you do p == p + 1 then compiler will first do the additon: p+1 then comparison, so you will have 0x80000000 == 0x80000008 which results in false.

Now to your code:

cout << p == p + 1;

is actually equivalent to:

(cout << p) == p + 1;

and that is because << has higher precedence than ==. Actually you should get a compilation error for this.

Another thing is comparision of pointers of non related types like double* with int*, without cast it should not compile.

marcinj
  • 48,511
  • 9
  • 79
  • 100
1

In C and C++ pointer arithmetic is very closely tied with array manipulation. The goal is that

int array[3] = { 1, 10, 100 };
int *ptr     = { 1, 10, 100 };

std::cout << array[2] << '\n';
std::cout << *(ptr + 2)  << '\n';

outputs two 100s. This allows the language to treat arrays and pointers as equivalent - that's not the same thing as "the same" or "equal", see the C FAQ for clarification.

This means that the language allows:

int array[3] = { 1, 10, 100 };
int *ptr     = { 1, 10, 100 };

And then

std::cout << (void*)array << ", " << (void*)&array[0] << '\n';

outputs the address of the first element twice, the first array behaves like a pointer.

std::cout << (void*)(array + 1) << ", " << (void*)&array[1] << '\n';

prints the address of the second element of array, again array behaving like a pointer in the first case.

std::cout << ptr[2] << ", " << *(ptr + 2) << '\n';

prints element #3 of ptr (100) twice, here ptr is behaving like an array in the first use,

std::cout << (void*)ptr << ", " << (void*)&ptr[0] << '\n';

prints the value of ptr twice, again ptr behaving like an array in the second use,

But this can catch people unaware.

const char* h = "hello";  // h points to the character 'h'.
std::cout << (void*)h << ", " << (void*)(h+1);

This prints the value of h and then a value one higher. But this is purely because the type of h is a pointer to a one-byte-sized data type.

h + 1;

is

h + (sizeof(*h)*1);

If we write:

const char* hp = "hello";
short int* sip = { 1 };
int* ip = { 1 };

std::cout << (void*)hp << ", " << (void*)(hp + 1) << "\n";
std::cout << (void*)sip << ", " << (void*)(sip + 1) << "\n";
std::cout << (void*)ip << ", " << (void*)(ip + 1) << "\n";

The first line of output will show two values 1 byte (sizeof char) apart, the second two values will be 2 bytes (sizeof short int) apart and the last will be four bytes (sizeof int) apart.

The << operator invokes

template<typename T>
std::ostream& operator << (std::ostream& stream, const T& instance);

The operator itself has very high precedence, higher than == so what you are actually writing is:

(std::cout << p) == p + 1

what you need to write is

std::cout << (p == p + 1)

this is going to print 0 (the result of int(false)) if the values are different and 1 (the result of int(true)) if the values are the same.

kfsone
  • 23,617
  • 2
  • 42
  • 74
0

If you want to print the value of a pointer, you can cast it to void *, for example:

cout << static_cast<void*>(p) << endl;

A void* is a pointer of indefinite type. C code uses it often to point to arbitrary data whose type isn’t known at compile time; C++ normally uses a class hierarchy for that. Here, though, it means: treat this pointer as nothing but a memory location.

Adding an integer to a pointer gets you another pointer, so you want to use the same technique there:

cout << static_cast<void*>(p+1) << endl;

However, the difference between two pointers is a signed whole number (the precise type, if you ever need it, is defined as ptrdiff_t in <cstddef>, but fortunately you don’t need to worry about that with cout), so you just want to use that directly:

cout << (p+1) - p << endl;
cout << reinterpret_cast<char*>(p+1) - reinterpret_cast<char*>(p) << endl;
cout << (q - p) << endl;

That second line casts to char* because the size of a char is always 1. That’s a big hint what’s going on.

As for what’s going on under the hood: compare the numbers you get to sizeof(*p) and sizeof(*q), which are the sizes of the objects p and q point to.

Davislor
  • 14,674
  • 2
  • 34
  • 49
0

Perhaps a picture will help (For a 64bit machine)

enter image description here

p is a 64bit pointer to a 32bit (4byte) int. The green pointer p takes up 8 bytes. The data pointed to by p, the yellow int val takes up 4 bytes. Adding 1 to p goes to the address just after the 4th byte of val.

Similar for pointer q, which points to a 64bit (8byte) double. Adding 1 to q goes to the address just after the 8th byte of valD.

robor
  • 2,969
  • 2
  • 31
  • 48
0

The pointer values that are printed are likely to change on every execution (see why the addresses of local variables can be different every time and Address Space Layout Randomization)

  • I get an answer of 00EFF680 for everytime I compare the adresss p with another pointer.

    int val = 20;
    double valD = 20;
    int *p = &val;
    cout << p == p + 1;
    

    It is translated into (cout << p) == p + 1; due to the higher precedence of operator << on operator ==.

    It print the hexadecimal value of &val, first address on the stack frame of the main function.

    Note that in the stack, address are decreasing (see why does the stack address grow towards decreasing memory addresses).

  • I get an answer of 00EFF670 for everytime I compare the address of q with another pointer.

    double *q = &valD;
    cout << q == q + 1;
    

    It is translated into (cout << q) == q + 1; due to the precedence of operator << on operator ==.

    It prints the hexadecimal value of &valD, second address on the stack frame of the main function.

    Note that &valD <= &val - sizeof(decltype(valD) = double) == &val - 8 since val is just after valD on the stack. It is a compiler choice that respects some alignment constraints.

  • I get an answer of 15726208 when I look at the pointer value of p.

    cout << (unsigned long)(p) << endl;
    

    It just prints the decimal value of &val

  • And I get an answer of 15726212 When I look at the pointer value of p + 1.

    int *p = &val;
    cout << (unsigned long) (p + 1) << endl;
    

    It prints the decimal value of &val + sizeof(*decltype(p)) = &val + sizeof(int) = &val + 4 since on your machine int = 32 bits

    Note that if p is a pointer to type t, p+1 is p + sizeof(t) to avoid memory overlapping in array indexing.

    Note that if p is a pointer to void, p+1 should be undefined (see void pointer arithmetic)

  • I get an answer of 15726192 when I look at the pointer value of q

    cout << (unsigned long)(q) << endl;
    

    It prints the decimal value of &valD

  • And I get an answer of 15726200 Wehn I look at the pointer value of q + 1.

    cout << (unsigned long) (q + 1) << endl;
    

    It prints the decimal value of &val + sizeof(*decltype(p)) = &valD + sizeof(double) = &valD + 8

Community
  • 1
  • 1
Franck
  • 1,635
  • 1
  • 8
  • 11