9

i have asked this question in a written test. while running the below code on my lapi, i am getting 10 as output

#include<stdio.h>
int main()
{
  int *i, *j;/* two pointer variable*/
  i = (int *)60;
  j = (int *)20;
  printf("%d \n",i-j);
  return 0;
}

Output :

10 

Can anyone tell me why the output is 10.

alk
  • 69,737
  • 10
  • 105
  • 255
Sushil
  • 163
  • 1
  • 1
  • 6
  • 1
    Related if not a duplicate (or shall be better tag the linked question being a duplicate to the current question?): http://stackoverflow.com/q/9855482/694576 – alk Jan 11 '15 at 10:29
  • @Clifford , Probably "lappy" which means "laptop" – Spikatrix Jan 11 '15 at 12:30
  • @CoolGuy : I know; the question was rhetorical, intended to encourage improvement. That said, the form-factor of the execution platform is hardly rellevant. – Clifford Jan 11 '15 at 16:07

6 Answers6

13

According to the C Standard (6.5.6 Additive operators)

9 When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object; the result is the difference of the subscripts of the two array elements.

So your program has undefined behaviour because the pointers do not point to elements of the same array.

Nevertheles it seems that the compiler simply generates an object code for subtracting two pointers irrespective of whether the pointers point to elements of the same array (it trusts you).

In this case the difference between the two pointers according to the pointer arithmetic is the number of elements that can be placed in the memory between two pointers.

In your case the sizeof( int ) is equal to 4. So a memory that has size of 40 bytes can accomodate 10 elements of type int provided that sizeof( int ) is equal to 4.

This value that is 10 is outputed by the printf function.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
8

You are evaluating the difference, or "distance" between two pointers to int. sizeof(int) is 4 on your platform. The difference between 60 and 20 is 40, which is the distance between 10 ints. Your implementation seems to be simply evaluating this difference.

However, the C standard places a restriction on the evaluation of the difference between two pointers: both pointers must point to elements in an array, or one past the end. If you can ensure both i and j satisfy this, then the difference evaluation is valid. Since your code does not necessarily satisfy that condition, it may have undefined behaviour, in which case the output/outcome could have been anything.

Also note that is is undefined behaviour to de-reference i and j unless they point to valid addresses holding int values.

juanchopanza
  • 223,364
  • 34
  • 402
  • 480
  • Sounds correct, but is this the case? Considering that the code is "wrong"? I think 10 might be a garbage number here. – Lews Therin Jan 11 '15 at 10:07
  • @LewsTherin Why is it wrong? – juanchopanza Jan 11 '15 at 10:08
  • I'd like to know if the OP always gets 10 as the output. And compare this with "correct" addresses. – Lews Therin Jan 11 '15 at 10:10
  • @LewsTherin And how do you know those addresses are not correct on some platform? – juanchopanza Jan 11 '15 at 10:10
  • That's exactly why I'm wondering how right this question/answer is? :S At least with the address operator I 100% know that the addresses are correct on every platform. – Lews Therin Jan 11 '15 at 10:13
  • And even question is good. if i do printf("%d \n",i) or j separately then it points to constant as assigned. and if we take difference then it points to sizeof? How? – Avinash Jan 11 '15 at 10:15
  • 1
    @LewsTherin I have qualified the answer specifying the conditions `i` and `j` must satisfy for the code to be well defined behaviour. – juanchopanza Jan 11 '15 at 10:29
4

Taking the difference of two pointers is defined by the C Standard only if both pointers point to the same (array) object (or one behind), so the OP's code invokes undefined behaviour. The result could be anything.

From the C11 Standard:

6.5.6/9 Additive operators

When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object; the result is the difference of the subscripts of the two array elements. The size of the result is implementation-defined, and its type (a signed integer type) is ptrdiff_t defined in the <stddef.h> header. If the result is not representable in an object of that type, the behaviour is undefined.

The following code is valid:

#include <stdio.h>

int main()
{
  int a[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

  int * i = a + 0;
  int * j = a + 10; /* Points "one past the last element" of the array. */

  printf("%td \n", i - j);

  return 0;
}

It also prints 10.

alk
  • 69,737
  • 10
  • 105
  • 255
3

Taking the difference between pointers that do not point inside the same object is Undefined Behaviour.

Your pointers do not point to any object at all.

It is Undefined Behaviour to subtract the pointers in your code.

Any result (10, 40, 65535, -1) is erroneous.

pmg
  • 106,608
  • 13
  • 126
  • 198
1

What you are seeing is undefined behavior.

Pointer should point to some valid memory location and 60 and 20 are not.

Just to quote from the standard

Both pointers shall point to elements of the same array object, or one past the last element of the array object since this is not what you see in your code this is UB.

Gopi
  • 19,784
  • 4
  • 24
  • 36
  • You are right, it is UB unless the addresses in question happen to be addresses of elements of an array (or one past the end) – juanchopanza Jan 11 '15 at 10:25
  • @juanchopanza The min I saw this code I knew this is UB but just it took someone else to pull the standards ref – Gopi Jan 11 '15 at 10:26
  • The point is, you cannot know for sure. `60` and `20` could in fact point to elements in the same array. So it is good to lay out the conditions. – juanchopanza Jan 11 '15 at 10:31
1

While it is strictly undefined behaviour and anything is allowed to happen, however compilers are seldom arbitrary in their treatment of of such code and the result can be explained in this case as:

    (i - j) == ((60 - 20) / sizeof(int))

But be aware that in some circumstances it may not apply; it may for example be dependent on the target memory architecture, or the relative alignment of the objects.

Clifford
  • 88,407
  • 13
  • 85
  • 165
  • Then what about i+j? cause output on my PC is 60. – Avinash Jan 11 '15 at 10:30
  • 2
    The + operator is not defined for pointer types, so such an expression would not even compile. Adding pointers makes no semantic sense whatsoever. The difference between two object addresses indicates the number of objects between the two pointers, which is useful. The sum of two addresses on the other hand is meaningless. – Clifford Jan 11 '15 at 10:33
  • @Avinash : How did you even get `i + j` to compile let alone result in 60!? `(int)i + (int)j == 80`, but you have to force reinterpretation as integers for the `+` to be valid. Equally if you were to print the pointer value `i` using the `%d` format specifier, that would reinterpret the address as an integer at runtime. The *pointer-diff* operator is not the same as an *integer-diff* despite having the same symbol (`-`) - it is overloaded, and yields the number of objects of the type pointed to that fit between the two addresses. – Clifford Jan 11 '15 at 10:51