Mohammad Jaber
Mohammad Jaber

Reputation: 63

Subtracting two pointers giving unexpected result

#include <stdio.h>

int main() {
    int *p = 100;
    int *q = 92;
    printf("%d\n", p - q);  //prints 2
}

Shouldn't the output of above program be 8?

Instead I get 2.

Upvotes: 0

Views: 1624

Answers (5)

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726479

Undefined behavior aside, this is the behavior that you get with pointer arithmetic: when it is legal to subtract pointers, their difference represents the number of data items between the pointers. In case of int which on your system uses four bytes per int, the difference between pointers that are eight-bytes apart is (8 / 4), which works out to 2.

Here is a version that has no undefined behavior:

int data[10];
int *p = &data[2];
int *q = &data[0];
// The difference between two pointers computed as pointer difference
ptrdiff_t pdiff = p - q;
intptr_t ip = (intptr_t)((void*)p);
intptr_t iq = (intptr_t)((void*)q);
// The difference between two pointers computed as integer difference
int idiff = ip - iq;
printf("%td %d\n", pdiff, idiff);

Demo.

Upvotes: 13

JeremyP
JeremyP

Reputation: 86651

These are integer pointers, sizeof(int) is 4. Pointer arithmetic is done in units of the size of the thing pointed to. Therefore the "raw" difference in bytes is divided by 4. Also, the result is a ptrdiff_t so %d is unlikely to cut it.

But please note, what you are doing is technically undefined behaviour as Sourav points out. It works in the most common environments almost by accident. However, if p and q point into the same array, the behaviour is defined.

int a[100];
int *p = a + 23;
int *q = a + 25;

printf("0x%" PRIXPTR "\n", (uintptr_t)a); // some number
printf("0x%" PRIXPTR "\n", (uintptr_t)p); // some number + 92
printf("0x%" PRIXPTR "\n", (uintptr_t)q); // some number + 100
printf("%ld\n", q - p); // 2

Upvotes: 0

Sourav Ghosh
Sourav Ghosh

Reputation: 134286

Your code is undefined behavior.

You cannot simply subtract two "arbitrary" pointers. Quoting C11, chapter §6.5.6/P9

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. [....]

Also, as mentioned above, if you correctly subtract two pointers, the result would be of type ptrdiff_t and you should use %td to print the result.


That being said, the initialization

 int *p = 100;

looks quite wrong itself !! To clarify, it does not store a value of 100 to the memory location pointed by (question: where does it point to?) p. It attempts to sets the pointer variable itself with an integer value of 100 which seems to be a constraint violation in itself.

Upvotes: 2

Saji Tibi
Saji Tibi

Reputation: 11

According to the standard (N1570)

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.

Upvotes: 1

AnT stands with Russia
AnT stands with Russia

Reputation: 320381

This

int *p = 100;
int *q = 92;

is already invalid C. In C you cannot initialize pointers with arbitrary integer values. There's no implicit integer-to-pointer conversion in the language, aside from conversion from null-pointer constant 0. If you need to force a specific integer value into a pointer for some reason, you have to use an explicit cast (e.g. int *p = (int *) 100;).

Even if your code somehow compiles, its behavior in not defined by C language, which means that there's no "should be" answer here.

Upvotes: 2

Related Questions