0
int main(void) {
    int *a;
    int *b = a++;
    printf("%d\n",b-a);
    return 0;
}

I expected the output to be 1 why is it -1?

Assume in the above question instead of a++ I have ++a.

Is it still undefined behavior?

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
Gopi
  • 19,784
  • 4
  • 24
  • 36
  • What did you got ? – ThisaruG Nov 21 '16 at 06:44
  • 9
    Because `b = a++` assigns `a` to `b` and then increments `a` (which doesn't affect `b`). – Cairnarvon Nov 21 '16 at 06:46
  • Hint: `printf("%d\n",b-a);`? Cm'on, you know the rest, :) – Sourav Ghosh Nov 21 '16 at 06:46
  • Difference between unrelated pointer invokes undefined behavior. Both should point to a the same array or one of them should point to one past that array. – haccks Nov 21 '16 at 06:47
  • @haccks What do you mean by unrelated pointers? Both are of same type int – Gopi Nov 21 '16 at 06:48
  • 2
    The only undefined behaviour here is using an uninitialized `a`. – Carl Norum Nov 21 '16 at 06:49
  • 2
    @haccks is right. pointer arithmetic only makes sense when both the pointers are pointing at the members of the same array. In this case it might be clear, but one cannot ignore the fact that this is undefined behaviour wrt the standard. – Haris Nov 21 '16 at 06:50
  • @SouravGhosh I didn't get your hint . Please explain – Gopi Nov 21 '16 at 06:52
  • 1
    @Carl; C11-§6.5.6/8: *If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined* – haccks Nov 21 '16 at 06:53
  • 3
    telling someone their code has undefined behaviour when said undefined behaviour is trivial to correct and anyway doesn't affect the actual problem the OP is asking about is pretty non-constructive. Thanks to @Cairnarvon for being helpful to OP. – Carl Norum Nov 21 '16 at 07:06
  • The discussion at [Check if pointer points to given array](http://stackoverflow.com/questions/40325787/check-if-pointer-points-to-given-array) may be useful. Also, be aware that on some hardware (when it's a problem, it's usually on mainframe-like hardware that has complex pointer organizations), even reading an invalid (uninitialized) pointer — without dereferencing it — may lead to unexpected behaviour (core dumps, etc). – Jonathan Leffler Nov 21 '16 at 07:22
  • @CarlNorum, I think if the said undefined behaviour wasn't effecting the result, then the answer would have been `0`. correct me if I'm wrong. – Haris Nov 21 '16 at 07:30
  • 2
    @Haris-- No. If `a` were initialized, the statement `b = a++` assigns the value of `a` to `b`, and then increments the value of `a`. In this case, `b - a` is not `0`. – ad absurdum Nov 21 '16 at 07:36
  • If `a` was initialized in the above code and ignoring the other undefined behaviour (its very hard for me to do that though), then `a - b` would have been `1`, and `b - a` would have been `-1`. Hmm, my bad. – Haris Nov 21 '16 at 07:38
  • 1
    @Haris-- I don't think that there is undefined behavior here if `a` is initialized and the format specifier in the `printf()` is fixed. Then `a` could safely be assigned to `b`, and it is perfectly legal to increment `a` by one, and also legal to then perform the subtraction `b - a`. – ad absurdum Nov 21 '16 at 08:14

6 Answers6

4

The First problem, as I see here, is primarily with

 int *a;

a is automatic local, and the initial value is indeterminate (no explicit initialization), hence doing a++ (or, ++a, for the matter) invokes undefined behavior.

That said, regarding the pointer subtraction, see this answer on why we need the operands of subtraction operator to be address of elements from same array object.

Finally, the subtraction of two pointers produce the type ptrdiff_t, you should be using %td to print the result. Otherwise, you again invoke UB.


[As mentioned in below comments]

Assuming the pointers are initialized properly, something like

int k[5] = {0};
int * a = &(k[0]);
int *b = a++;
printf("%td\n",b-a);

in that case, the result will be -1, as that is the difference in the index of both the elements (remember a++ is post-increment).

Chapter §6.5.6/9, C11 standard

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.

Community
  • 1
  • 1
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • I am *not* the down-voter. Just wanted to ask, why is `a++` UB here? AFAIK, here `a` is a pointer (and is already placed on the stack) and `a++` will increase the address stored in `a` by 4 or 8 or whatever. I think `(*a)++` would be UB. Please tell me what I am missing. – babon Nov 21 '16 at 07:21
  • @babon are you confusing `a` with `&a`? `a++` is UB based on the same logic, if `a` would haven been an `int`, either. – Sourav Ghosh Nov 21 '16 at 07:27
  • And what would be the result, if the pointer were correctly initialized? OP is expecting 1... – Bob__ Nov 21 '16 at 07:33
  • @Bob__ It will be `-1`. for `a++` (b is _before_ increment), `++a` does not make much sense, both will be pointing to same element, anyway then. – Sourav Ghosh Nov 21 '16 at 07:44
  • Of course, and I think you should add that to the answer. – Bob__ Nov 21 '16 at 07:59
  • Thanks for the explanation. – babon Nov 21 '16 at 08:16
  • @Bob__ Not very sure if that's too much of _assumption_ from our side, but updated, anyway. – Sourav Ghosh Nov 21 '16 at 08:16
4

First of all, your code causes undefined behavior because it reads and modifies uninitialized variables.

Also the specifier %td should be used for printing pointer difference.

Let's assume the pointer a actually points to a valid object:

int i;
int *a = &i;
int *b = a++;
printf("%td\n",b-a);

The postfix ++ operator gives the current value of the operand and then increments the operand by one. The above code is identical to:

int i;
int *a = &i+1;
int *b = &i;
printf("%td\n",b-a);

Pointer a points to one-past the object i, and pointer b points to the object i. The subtraction will, due to pointer arithmetic, yield -1. If the operation was: a-b then the result would be 1.

This is defined behavior.

2501
  • 25,460
  • 4
  • 47
  • 87
3

Difference of two pointers ((b-a) in this case) is not defined in C unless the two pointers are pointing to addresses of a same array.

Also, since the pointer 'a' in your code has not been assigned any address ( contains garbage value ), doing any kind of operation is a sin.

If you wish to see how does subtraction of two pointers work, then try to define an array and make these two pointers point to it.

Akash Mahapatra
  • 2,988
  • 1
  • 14
  • 28
  • 4
    `...are pointing to addresses of a same array` + `or one past the last element of the array` – Support Ukraine Nov 21 '16 at 07:14
  • And what would be the result, if the pointer were correctly initialized? OP is expecting 1... – Bob__ Nov 21 '16 at 07:33
  • @Bob__ Generally , we do (b-a) to get the number of elements of the array between these two pointers. but because of int *b = a++; the result will be -1, which is of no use – Akash Mahapatra Nov 21 '16 at 08:08
0

When you increment the pointer, it does not add the value to 1. It just tells the pointer to point to the next location. Also, your pointers were never initialized and they are just pointing to random garbage numbers.

tigris_kn
  • 1
  • 1
0

int *a is a variable with automatic storage duration and never has its address taken (&a). The code therefore invokes undefined behavior (as per 6.3.2.1, see this) and your program can't have any predictable outcome.

Using the %d format specifier on on a ptrdiff_t also invokes undefined behavior (7.21.6.1/9). You should use %td for ptrdiff_t and %p for pointers.

Thus you can't expect anything from your program. It can output anything, or nothing, or crash.

Community
  • 1
  • 1
Lundin
  • 195,001
  • 40
  • 254
  • 396
-1

That is no undefine behaviour

when you declared *a, a points to a memory location, *b = a++; b to point to the same location as a, AND increaments a to point to a location 1 factor greater than the previous location that b points to.

b - a = -1 //correct

i'll give example

int main(void)
     {
        int *a; // 0x408
        int *w = a++; // 0x400
        int *b = a++; // 0x404

        int c = (b-a);
        printf("%d\n",b-a);// -1
        printf("%d\n",w-a); // -2

        return 0;
    }

i intruduce w to better ilustrate

The run-time memory address of the variable will look similar to the ones above.

b - a ( 0x404 - 0x408) == -1( -4 );

the sizeof int( in this case ) is 4 bytes. and pointers holding the address of int will have their address changing(+/-) by factor of 4, as far is int is concern in this case 4 bytes hold one integer(1 unit)

w - a == (0x400 - 0x408) = -2( -8 )

if you had

a - w == (0x408 - 0x400) = 2( 8 )

ytobi
  • 535
  • 1
  • 9
  • 19