1

The following program gives -1, but I expected it to print 1:

#include <iostream>
int main()
{
    int a[] = {0, 1};
    int* p = a;
    int* p2 = a+1;

    std::cout << p - p2 << std::endl;
    system("PAUSE");
    return 0;
}

If I swap the subtraction around like this:

std::cout << p2 - p << std::endl;

Then I get exactly 1.

The answer to Pointer subtraction confusion says that if we subtract pointer from pointer, we get the amount of blocks of memory lying between them, and I don't see that this can be negative.

I'm expecting to get exactly the same result for p - p2 and p2 - p.

Toby Speight
  • 23,550
  • 47
  • 57
  • 84
  • You should subtract `p` from `p2`, not the other way around. -1 is correct for what you have (one memory block from first block, zero number). – Resurrection Dec 07 '16 at 12:10
  • For the sake of experiment, i tried to do reverse and i like the answer i get, but when i do the first one, which gives me -1, i'm confused. What this -1 mean? –  Dec 07 '16 at 12:12
  • let's say a[0] adress is 0x01, a[1] is 0x02, so p - p2 is 1 - 2 is -1 – Lukasz Dec 07 '16 at 12:16
  • 1
    Think of it this way. You're essentially evaluating `a - (a + 1)` which is `a - a - 1` which is `-1`. The value of `a` is meaningless. – Rotem Dec 07 '16 at 12:17
  • @TobySpeight i'm confused because of the [link](http://stackoverflow.com/questions/3238482/pointer-subtraction-confusion), which says about the amount of memory blocks between pointers as a result of substracting. –  Dec 07 '16 at 12:28
  • @Tracy it's not correct that you get the absolute number of elements between pointers when you subtract them. What you get is the difference between the element indexes, expressed as the index which the first pointer refers to minus that which the second pointer refers to. – davmac Dec 07 '16 at 12:30
  • @Tracy Think of it this way: Memory can be addressed per byte. Each byte would have address starting from 0. Type - like int - takes certain amount of bytes to store (on most systems 4) and you can get that with sizeof(T) function. Now pointer arithmetics is here to spare you the use of sizeof(T) so it does that for you and gives you the difference between the adresses divided by that. And since addresses are numbers then when you subtract address a (say 8) from another (say 4) and divide it with sizeof(T) that is 4 for int you get -1 and what you observe. – Resurrection Dec 07 '16 at 12:34
  • @davmac that simple? i was thinking that there are 3 layers at least: memory addresses, indecies, values. What of these 3 i'm operate on when substracting/adding pointers to each other? I can use indices without applying pointers so it's not them, the access i get to the values is relying upon the indices so it's not them too, the memory addresses are left so i somehow iterate through them but you say i get the difference between the indices. –  Dec 07 '16 at 12:37
  • @Tracy As long as the two pointers point to elements within the same array, then yes, it's that simple. You can consider it be indices or memory addresses that you are operating on, but the result is expressed in indices so I prefer to think of it that way. Also, that is how it is formally defined. – davmac Dec 07 '16 at 12:39
  • I think you mean to write `p2 -p` in the "If i put it like this" part, otherwise the two lines are identical – 463035818_is_not_a_number Dec 07 '16 at 12:43

4 Answers4

3

You subtract p2 (pointer to second element) from p (pointer to first element). Lets say p is memory at address that is equivalent to number 1000 (when converted to int). p2 then will be 1000 + sizeof(int) or 1004 on most systems. Pointer arithmetic is:

(address - address2) / sizeof(T)

where T is your type. Therefore when you do:

p - p2 //(1000 - 1004) / 4

you get -1. If you do the opposite you get 1.

Resurrection
  • 3,462
  • 2
  • 27
  • 47
  • @M.M Fundamental type in C++ is byte. If you work with pointers to bigger types (like `int`) you will see e.g. `p1` is `1505216` and `p2` is `1505220`. So you will expect that when you add or subtract them you will get 4 or -4. Instead you get 1 and -1. Huh? And then someone tells you don't worry, it's pointer arithmetics (aka magic) and it works like that. Or maybe you try to explain what is happening and you may of course add that standard mandates that behaviour and this is the most common way how it is done. You may consider the explanation an unnecessary detail. That is where we disagree. – Resurrection Dec 07 '16 at 13:43
  • I expect that when I subtract `&a[0]` and `&a[1]`, I get `-1`, regardless of how each pointer might be stored in memory. This is because I know the rules of C++. Your last comment shows exactly the danger of basing an understanding on implementation details: it leads to false expectations. There is nothing complicated and nothing magic about the rule `&a[X] - &a[Y] == X - Y`. Your explanation either adds unnecessary complication (on a system that does have the implementation details your answer relies on), or is wrong (on a system that does not store pointers in that way). – M.M Dec 07 '16 at 13:51
2

You get -1 because that is the amount you must add to p2 to reach p. Subtraction is the inverse operation to addition.

Pointer arithmetic works in units of the pointed-to type, in this case int. p is set to point to a[0] and p1 points to a[1]. In other words, p + 1 == p2 and p2 - 1 == p.

Pointer types in C++ are an abstraction, and like all abstractions, it's best (most of the time) to use the abstraction - in this case, that means not needing to worry about machine addresses and the size of types when doing pointer arithmetic. If you ensure that the type is correct, then you can step through arrays simply by the number of elements, regardless of their size.

It is useful to understand how the abstraction is implemented by the machine, and essential to know when you need to look 'under' the abstraction; such situations include union types and the use of reinterpret_cast<>().

Toby Speight
  • 23,550
  • 47
  • 57
  • 84
  • "It's usually best not to worry about machine addresses and the size of types when doing pointer arithmetic" - 100% agree. – davmac Dec 07 '16 at 12:43
  • @davmac I respectfully disagree. OP asked for explanation how pointer arithmetics work. This answer says "It's usually best not to worry about machine addresses and the size of types when doing pointer arithmetic". How does that answer the question? Or help OP understand the topic? Or you really believe that OP should trust our word that it works and do not concern themselves with how and why it works the way it does? Size of types and machine addresses are the very things that explain it. – Resurrection Dec 07 '16 at 12:49
  • 1
    Perhaps I misphrased things. C++'s pointer types are an abstraction. Like all abstractions, it's helpful to have an understanding of how the abstraction is implemented, but *most of the time* one should be able to lean on the abstraction and let it do its job. (and you should know when you need to look 'under' the abstraction) – Toby Speight Dec 07 '16 at 12:56
  • @TobySpeight I absolutely agree with the point that when using pointer arithmetics one should not worry about how it works. In this case however I believe the question was about how it works rather than how to use it. But I understand you now better. Cheers. :-) – Resurrection Dec 07 '16 at 12:57
  • @michael - is it clearer now what I meant about trusting the abstraction? – Toby Speight Dec 07 '16 at 13:02
  • 1
    The question has now been edited - seems the OP was confused about getting a signed result, rather than (as usual with pointer arithmetic) about the magnitude/units of the result. It appears that my answer still stands in the light of this new information. – Toby Speight Dec 07 '16 at 13:04
  • @TobySpeight Yes. ;-) – Resurrection Dec 07 '16 at 13:07
  • 1
    @MichaelVlach pointer arithmetic works the same regardless of size of types and machine addresses. So I do not think those details make up "how it works". – M.M Dec 07 '16 at 13:07
  • @MichaelVlach as I read the question it is about why a specific expression gives a specific result, not how pointer arithmetic works at the machine level. The answer to why the expression returns -1 is best understood without worrying about machine addresses etc. – davmac Dec 07 '16 at 13:08
  • @M.M I am genuinely interested in how you can explain how pointer arithmetics work (and give you the result you see) without any reference to type sizes or machine addresses. Pretty much all the answers around that omit these "details" require the reader to believe that it works as that person says. The whole confusion is exactly about this misunderstanding. The person wants to know how the abstraction is achieved, not that it exists IMO. – Resurrection Dec 07 '16 at 13:11
  • @MichaelVlach my answer explains how it works, as does this one. But based on your comments, I think that by "how it works" you actually mean something like "what assembly instructions would be generated on some CPU I am familiar with, if the compiler didn't do any optimization". In other words , the translation between C++'s abstract definition, and a particular set of hardware. I don't think OP was asking about that. – M.M Dec 07 '16 at 13:15
1

From the C++ Standard definition of pointer subtraction:

When two pointers to elements of the same array object are subtracted, the result is the difference of the subscripts of the two array elements.

"difference" means subtraction. So in code this says that &arr[X] - &arr[Y] is X - Y. This could be positive or negative depending on whether X or Y is greater.

In your code a means &a[0], and a+1 means &a[1]. So when you do a - (a+1) it is the same as &a[0] - &a[1], which is -1 according to the above rule.

M.M
  • 130,300
  • 18
  • 171
  • 314
-3

Pointer is just an address or a number with a double type size (in most cases) so ofc when you add one to p then the difference will be one..

Dr.Haimovitz
  • 1,372
  • 8
  • 14
  • I have not downvoted yet... but your answer is incorrect and self contradictory. You would have to cast the pointer type (to say `char *`) to get the number of bytes difference as you say.And on one hand you say of course the difference is one and then say it is the number of bytes. – PeterSW Dec 07 '16 at 12:28
  • Maybe you missunderstand me , I say that there is a difference between adding one to a pointer and using ++ operator – Dr.Haimovitz Dec 07 '16 at 12:31
  • 1
    "add one to p after setting it to a: (p++) and then do the substruction you will get the size of integer (in bytes )" - this is just plain incorrect. – davmac Dec 07 '16 at 12:32
  • 1
    @Dr.Haimovitz I hadn't tried it, because I know C well enough. But here you go: http://ideone.com/Yzc9ov - prints 1, which is definitely not the size of `int` in bytes (which is 4 on that target). – davmac Dec 07 '16 at 12:35
  • @drh, please explain the "*difference between adding one to a pointer and using ++ operator*", because the Standard says there is no such difference. – Toby Speight Dec 07 '16 at 12:36
  • So are you claiming that `p++` gives a different value to `p += 1`? That is clearly incorrect. – PeterSW Dec 07 '16 at 12:37
  • p++ adds the size of int to p if p is int , thats what im caliming – Dr.Haimovitz Dec 07 '16 at 12:41
  • Maybe i was missunderstood : what i have tried to say is that p++ adds the size of int to p if p is int . – Dr.Haimovitz Dec 07 '16 at 12:42
  • @Dr.Haimovitz what you are claiming is incorrect, as the example I posted shows. – davmac Dec 07 '16 at 12:42
  • @davmac it does not show it because it show the answer as in int size... think about it: if you have an int pointer thats point to 100 and if p++ is only get the pointer to 101 so you basicly saying that one needs to do p+=sizeof(int) to reach the next int... which is obviously not the case, btw my english is not so good so im having a bit of trouble to explain my self – Dr.Haimovitz Dec 07 '16 at 12:45
  • Btw you can print p before and after the ++ operation and you will notice that the value is 4 bytes bigger .. – Dr.Haimovitz Dec 07 '16 at 12:51
  • 1
    @Dr.Haimovitz you will notice the same thing if you do `p = p + 1` – M.M Dec 07 '16 at 13:04