0
main(){
    char a[20],*p,*q;
    p=&a[0];
    q=&a[10];
    printf ("%d\n",&q - &p) }

This C program gives o/p as:

1

As I understand, the values stored at those addresses are garbage. How can their subtraction be 1?

Can anyone please explain how?

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
spiders.here
  • 127
  • 2
  • 13
  • 1
    You are subtracting the addresses of p and q, not their contents. – Christian Gibbons Mar 13 '22 at 16:26
  • You should probably edit your question to explain what *you* expect and why. – G.M. Mar 13 '22 at 16:26
  • It has nothing to do with initialised arrays, but the placement of `p` and `q` on the stack. They must be adjacent here, but they don't have to be. – Weather Vane Mar 13 '22 at 16:26
  • 3
    `q` and `p` are two different pointers. They are not two different elements of the same array (of pointers). Therefore `&q - &p` is subtracting two pointers that do not point to elements of the same array (nor one past its end), and so the behavior is undefined. Note that what `q` and `p` themselves point to is entirely irrelevant; the array `a` has nothing to do with this question. – Nate Eldredge Mar 13 '22 at 16:27
  • Did you mean `*q - *p`? That would make more sense in the context. But even so, it could be anything, without any reason worth looking into. – Weather Vane Mar 13 '22 at 16:29
  • @ChristianGibbons Subtracting the addressee gives 10. Because they are 10 chars apart. – spiders.here Mar 13 '22 at 16:30
  • 2
    No, subtracting the addresses would be `q - p`. – Weather Vane Mar 13 '22 at 16:31
  • No, the addresses are the addresses of p and q which can be anywhere. The contents of p and q, which are pointers in this case, are themselves addresses inside the array. Get rid of the `&` address-of unary operator and you'll get the results you expect. – Christian Gibbons Mar 13 '22 at 16:32
  • @ChristianGibbons yes, removing the & sign results to 10. But with the & sign I expected it'd be some garbage value. – spiders.here Mar 13 '22 at 16:45
  • 1
    @spiders.here "But with the & sign I expected it'd be some garbage value" which is exactly what you got. – dbush Mar 13 '22 at 16:46

2 Answers2

1

q and p are two different pointer variables. They are not two different elements of the same array (of pointers). Therefore &q and &p are two pointers (to pointers) that do not point to elements of the same array (nor one past its end). Therefore evaluating &q - &p causes undefined behavior, and it is not possible to use the language definition to reason about what may or may not happen beyond that point.

See also Is subtraction of pointers not pointing to different elements of same array valid in C?.

What might be happening in your program is that q and p happen to be allocated at adjacent addresses on the stack, with q at a higher address than p, and that the compiler implements &q - &p by subtracting their actual addresses and dividing by their size. That would account for a value of 1. But the compiler is in no way obliged to do this; it could, in principle, instead print 47 or BUG or delete all your files.

Note that what q and p themselves point to is entirely irrelevant; the array a has nothing to do with your code as it stands.

You may have been thinking of doing q-p instead. That would be subtracting pointers to two different elements of the a array. It is perfectly well defined, and the result would be 10.

(By the way, the result of subtracting two pointers has type ptrdiff_t. You are using the printf specifier %x which is only valid for an argument of type unsigned; this causes undefined behavior as well. The correct format specifier would be %td.)

Nate Eldredge
  • 48,811
  • 6
  • 54
  • 82
  • Pardon me if I'm incorrect. Here p is pointing to 0th element, and q is pointing to 10th element. Isn't that pointing to the elements of the same array? – spiders.here Mar 13 '22 at 16:35
  • 2
    @spiders.here: Yes, and therefore evaluating `q-p` would be just fine. But that's not what you do; you evaluate `&q - &p` which is completely different. That is, `q` is a pointer to an element of the `a` array. But `&q` is a pointer to the variable `q` which is not itself in an array at all. – Nate Eldredge Mar 13 '22 at 16:38
  • I corrected the specifier to %d. And I guess I understand the result. Thanks – spiders.here Mar 13 '22 at 16:50
  • @spiders.here: `%d` is still wrong as `ptrdiff_t` is not the same as `int`. It really must be `%td`, or else you need to cast. – Nate Eldredge Mar 13 '22 at 16:54
0

This call

printf ("%x\n",&q - &p);

have undefined behavior because the pointer expressions &p and &q do not point to elements of the same array. That is the expression &p has the type char ** and points to the variable p while the expression &q having the same type char ** points to the variable q.

It seems you mean

printf ("%tx\n",q - p);

In this case the output will be hexadecimal value of 10 a.

Or if you will write

printf ("%#tx\n",q - p);

then the output will be

0xa
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • @NateEldredge You are mistaken. The length modifier t can be used with the conversion specifier x provided that the outputted value is not negative, – Vlad from Moscow Mar 13 '22 at 16:44
  • Is there a citation for that? The `t` length modifier is supposed to take an argument of type "`ptrdiff_t` or the corresponding unsigned integer type". By analogy with the other length modifiers, I presume this means "... depending on whether a signed or unsigned conversion specifier is being used". So `%tx` would need an argument whose type is the unsigned integer type corresponding to `ptrdiff_t` (which doesn't have a standard name AFAIK) but not `ptrdiff_t` itself. – Nate Eldredge Mar 13 '22 at 16:53
  • 1
    @NateEldredge "5 The values of any padding bits are unspecified.54) A valid (non-trap) object representation of a signed integer type where the sign bit is zero is a valid object representation of the corresponding unsigned type, and shall represent the same value." and (function calls) "— one promoted type is a signed integer type, the other promoted type is the corresponding unsigned integer type, and the value is representable in both types;" – Vlad from Moscow Mar 13 '22 at 17:03
  • @VladfromMoscow: The passage you quoted, from C 2018 6.5.2.2 6, does not apply to calling `printf`, possibly unless the program has declared it itself without including ``. That paragraph applies when the expression used to call the function does not include a prototype, but `` declares `printf` with a prototype. Later sentences subdivide this into cases where the function is defined with or without a prototype, but how the function is defined is separate from the type of the expression used to call it,… – Eric Postpischil Mar 13 '22 at 21:28
  • … and the passage you cite applies to the subcase in which the function is defined without a prototype, which we do not know to be true (it is an implementation detail). – Eric Postpischil Mar 13 '22 at 21:29