0

i have a question on pointer concept which i could not find a logical answer to

#include<conio.h>
#include<iostream.h>
void main()
{
    int arr[10];
    clrscr();
    cout<<*arr+5 - *arr+3;
    getch();
}

even if i assign arr[0]=10; (or any other value)

the compiler gives answer 8 but how . I can not see(understand) how operator precedence and associativity does solve it.

I will be grateful to you.

ashishdhiman2007
  • 807
  • 2
  • 13
  • 28
  • 4
    This is why I don't recommend writing all this in one line without any `()`. I prefer to handle operator precedence myself instead of leaving it to the compiler. – Lord Zsolt Jun 24 '14 at 13:21
  • 1
    @LordZsolt I disagree. Do you know [BODMAS](http://en.wikipedia.org/wiki/BODMAS)? Every preschooler learns it. Surely do you don’t want to tell me that you need parentheses around your pluses and minuses. In the same vein, programming languages have fundamental standard precedences which do not require them, and should not get cluttered by parentheses. – Konrad Rudolph Jun 24 '14 at 13:23
  • 2
    What result did you expect? – interjay Jun 24 '14 at 13:24
  • 2
    You seem to be learning from some very outdated source, since the C++ code you’ve posted is completely invalid, and any modern compiler will likely reject it. I suggest you take a look at the [definitive C++ book list](http://stackoverflow.com/q/388242/1968). – Konrad Rudolph Jun 24 '14 at 13:39
  • interjay no i do not expect any answer as such but want to know how it came out to be 8 – ashishdhiman2007 Jun 24 '14 at 13:58
  • @interjay ... and why? – Peter - Reinstate Monica Jun 24 '14 at 14:22

3 Answers3

4

Because of *arr - *arr is 0 and 5 + 3 is 8.

The result you may be expecting is the result of:

cout<<(*arr+5) - (*arr+3);
  • 2
    Who knows, it could also be (*(arr+5) - *(arr+3)) – stefaanv Jun 24 '14 at 13:23
  • 1
    @stefaanv But it can’t. – Konrad Rudolph Jun 24 '14 at 13:24
  • @KonradRudolph: Yep, I misread and I didn't even got your remark immediately. What I wanted to say is that he probably intended it this way (but then should initialize the array). The answer is a bit confusing as the result of `(*arr+5) - (*arr+3)` is 2, not 8. – stefaanv Jun 24 '14 at 13:29
4

The compiler gives answer 8 because that operation is simply equivalent to: (*arr - *arr) + 5 + 3 = 8. If you want to add the scalar to the pointer and then get the referenced value, you have to use parentheses *(arr+5).

  • Thanks Andrea . You are close to make me understand. (Appreciation for others too) . but as * has higher precedence , so doesn't it had to be that *arr gets solved first at both locations and then not changing their arrangement *arr+5-*arr+3 – ashishdhiman2007 Jun 24 '14 at 13:31
  • Sorry, I am not sure what you mean. The expression *arr+5-*arr+3 is equivalent to arr[0]+5-arr[0]+3. – Zaphod Beeblebrox Jun 24 '14 at 13:52
  • Andrea .. so why would both arr[0] would get solved to be a zero . i think that arr[0]+5 would be solved first by the compiler.. I am not just understanding the way compiler does it – ashishdhiman2007 Jun 24 '14 at 14:01
  • 1
    I don't understand, it's simple maths: a+b-a+c = b+c. Even if the compiler solves arr[0]+5 first, to calculate the final result it will have to subtract arr[0]. – Zaphod Beeblebrox Jun 24 '14 at 14:28
1

If you look at the precedence table, for example here:

http://en.cppreference.com/w/cpp/language/operator_precedence

then you'll notice that the dereference operator (*) has higher priority than addition/subtraction (+/-) operators (they are in group no. 3 and 6 respectively). This is why the first operation that is performed is getting the value that the arr variable is pointing to, i.e. this part:

*arr

After this, the addition/subtraction is performed. The value that arr is pointing to doesn't matter since it gets reducted anyway.

This is how you should read this expression:

(*arr) + 5 - (*arr) + 3

and (*arr) - (*arr) is 0, no matter what value it points to.

EDIT: What I've written above is apparently true in your case and your compiler, but look at the @Konrad Rudolph comments to this answer.

And, if you are curious, how the compiler knows if, for example, the '*' should be treated as multiplication or dereference operator: it resolves this problem by looking at the number of arguments - if there's only one, than it's derefence, and if there are two, then it's multiplying.

KjMag
  • 2,650
  • 16
  • 16
  • 2
    Actually, `(*arr) - (*arr)` in OP’s code isn’t 0, it’s undefined. Many compilers will *not* give the result OP observes (but then, the code is terrifying and invalid C++ anyway, and no modern compiler accepts it). – Konrad Rudolph Jun 24 '14 at 13:35
  • @KonradRudolph why undefined? The array is not initialised, but it's allocated on the stack. When you write *arr, the name of the array decays to the pointer to its first element and the pointed integer is accessed. Whatever that integer is, *arr-*arr is always 0. – Zaphod Beeblebrox Jun 24 '14 at 13:48
  • Thanks user3564091 . but a little more help on why (*arr) - (*arr) gets solved first not the way its said cout<<*arr+5 - *arr+3; as *arr+5 and *arr+3 are arithmetic operator having associativity of left to right – ashishdhiman2007 Jun 24 '14 at 13:57
  • 3
    It doesn't have to be solved first in order to zero. For example, let's say that *arr = 1000. Then, you have: 1000 + 5 - 1000 + 3, which equals 1005 - 1000 + 3, which equals 5 + 3, which equals 8. This will be true for any *arr value. This is basic math: the order of addition doesn't influence the final result. – KjMag Jun 24 '14 at 14:02
  • 3
    @Andrea No. Uninitialised access is undefined, regardless of the potential value of the pointee. Try compiling this with optimisations enabled on GCC: the value might surprise you. – Konrad Rudolph Jun 24 '14 at 14:10
  • Well, maybe you're right Konrad, but "undefined" doesn't mean that an implementation may not define that behavior in some way. You said that in OP's code *arr-*arr is not zero, but on his implementation, that's the value he's getting. – Zaphod Beeblebrox Jun 24 '14 at 14:27
  • 1
    @Andrea Laforgia, but that's the thing: if it is undefined, you cannot be sure if you're getting the results you're expecting by accident, or because it is the way the compiler works. Also, the compiler should not implement an undefined behaviour anyway, and you cannot be sure if this code stops working after some major update that would aim to comply with the standard. – KjMag Jun 24 '14 at 14:47
  • @user3564091 I agree. It is true that we can't tell whether that 8 is returned by mere accident or it's a defined behaviour for that platform. To be honest, however, I don't understand why an optimised compiler should even attempt to calculate that value. Isn't obvious that (*arr - *arr == 0) no matter whether the pointed values are initialised or not? Why undefined behaviour? – Zaphod Beeblebrox Jun 24 '14 at 15:07
  • 1
    @Andrea “Why undefined behaviour” because otherwise you’d have to explicitly define this case very specifically. It is clear that the more general case of reading an uninitialised value must be undefined. Why take the extra effort of defining the behaviour of one uninteresting special case? And as to what the optimiser does: it obviously doesn’t attempt to calculate any value. Rather, it yanks out the complete calculation and probably just outputs the value that currently happens to occupy the top of the stack or some register. – Konrad Rudolph Jun 24 '14 at 15:57
  • Okay, agreed on the reason this case is considered undefined behaviour as well. It's just an application of the general rule. It makes sense. What I don't understand, however, is how any optimised compiler might ever come up with a value different from 8 in such case. No matter whether *arr is undefined or not, shouldn't those two terms of the calculation be ignored because they cancel each other out? – Zaphod Beeblebrox Jun 24 '14 at 16:06
  • BTW what do you mean in one of your previous comments by "Uninitialised access"? What we have in this example is not an uninitialised pointer, as it's the name of an array, so it decays to the pointer to the first element of the array. The pointer is always valid. What is not initialised is the value pointed to. – Zaphod Beeblebrox Jun 24 '14 at 16:15