Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When I subtract memory addresses, why is the result smaller than I expected?

Tags:

c++

c

I have the following program:

#include <iostream>

struct X
{
    int a;
    float b;
} x[10], *p1, *p2;

int main(int argc, char *argv[])
{
    p1 = &x[1];
    p2 = &x[5];

    int i = p2 - p1;

    std::cout << i << std::endl;
}

I can visualize X's layout in memory, 10 boxes containing an int and a float, p1 will point at the beginning of the second box (x[1]) and p2 pointing at the beginning of the 6th box (x[5]):

   X   0   1  2  3  4  5  6  7  8  9
       _______________________________
    b  |__|__|__|__|__|__|__|__|__|__|
    a  |__|__|__|__|__|__|__|__|__|__|
          |           |    
          |           | 
          p1          p2

Is my drawing correct ? If so why is the result of i 4 ?
Having some difficulties understanding subtraction of two addresses ?

like image 586
Adrian Avatar asked Dec 02 '11 13:12

Adrian


1 Answers

This is how pointer arithmetic works. Consider:

p1 = (x*)100;   // invalid memory address, just an example!
p2 = p1 + 1; 

At this point, p2 will not have the value 101, but rather 100 + sizeof(x) (which let's say is 8, so 108). It has been incremented not by one, but by one multiple of sizeof(x)! Conversely, subtracting an integer from a pointer actually subtracts multiples of sizeof(the pointed to type).

So now if you do int diff = p2 - p1, you would certainly expect to get 1 back, not 8! Otherwise, subtracting the number you just added would not yield the original value. Therefore, subtracting one pointer from another yields not the difference in memory addresses but the number of elements between the two pointers.

Moreover, the standard mandates that pointer subtraction is meaningless unless the two pointers point to elements in the same array (more correctly, it's undefined behavior and you are also allowed to use a pointer to "one past the last element" even if there is no such object there).

Finally, what if the compiler does not know the size of the pointed to type (i.e. the pointers are void*)? In this case, pointer arithmetic is not allowed at all. For example:

void* p = 100;
void* x = p + 1; // does not compile¹

¹ Some compilers may provide pointer arithmetic on void* as an extension to the language specification. In this case this statement can indeed compile and the result would depend on the specification of said extension (e.g. gcc would end up with the value 101).

like image 127
Jon Avatar answered Nov 02 '22 17:11

Jon