Разница в указателе/адресе

Почему разница между двумя адресами неверна? http://codepad.org/NGDqFWjJ

#include<stdio.h>
int main()
{
   int i = 10, j = 20;
   int *p = &i;
   int *q = &j;
   int c = p - q;
   printf("%d\n", p);
   printf("%d\n", q);
   printf("%d", c);
   return 0;
}

Выход:

-1083846364
-1083846368
1

person Ava    schedule 24.03.2012    source источник


Ответы (3)


Во-первых, арифметика указателей не определена при выполнении над несвязанными указателями.

Во-вторых, это имеет смысл. При вычитании указателей вы получаете количество элементов между этими адресами, а не количество байтов.

Если бы вы попробовали это с

char *p1 = &i, *p2 = &j;

вы бы получили другой результат.


В качестве примечания используйте %p при печати указателей.

person cnicutar    schedule 24.03.2012
comment
Строго говоря, это правда, но каждая реализация, которую я когда-либо использовал, работает правильно. Как и ОП, на самом деле. - person Carl Norum; 25.03.2012
comment
Не могли бы вы подтвердить, что это справедливо и для C++ в соответствии со стандартом. (Я знаю, что это правда, но я хотел бы, чтобы это было изложено в письменном виде, если это возможно. Спасибо!) - person Dan Nissenbaum; 17.06.2014

Как уже говорили другие, результат, который вы получаете, кратен размеру типа, на который указывают указатели. Приведите их к указателям на символы, и результат, который вы получите, будет в байтах. Кроме того, следует использовать тип ptrdiff_t, чтобы в системах с 64-разрядными битовые указатели типа должны быть достаточно большими, чтобы вместить результат.

ptrdiff_t c = (char*)p - (char*)q;

Также обратите внимание, что получение разницы адресов двух значений, которые не находятся в одном и том же массиве, не определено в стандарте, но работает практически в каждой системе.

person Macil    schedule 24.03.2012
comment
Я получаю сообщение об ошибке для arithmetic on pointers to void, когда пытаюсь это сделать. - person Yu Chen; 06.11.2017
comment
Оказывается, арифметика с указателями void* является нестандартным поведением, поддерживаемым только некоторыми компиляторами с (out) определенными флагами. Я изменил ответ, чтобы вместо этого рекомендовать только указатели char*, которые работают правильно и являются стандартным поведением. - person Macil; 07.11.2017

Строго говоря, ваша программа вызывает несколько видов неопределенного поведения, сначала из-за арифметики указателей на несвязанных указателях, а затем из-за несоответствия строк формата и аргументов в ваших операторах печати. Однако, даже если бы они были исправлены, вы бы увидели те же результаты. Причина, по которой разница равна 1, заключается в том, что арифметика указателя дает результаты в единицах размера указанного типа - в вашем случае int является 4-байтовым типом, поэтому вычитание указателей int *, которые указывают на 4 байта друг от друга, дает результат 1.

person Carl Norum    schedule 24.03.2012