Путаница вычитания указателя - PullRequest
48 голосов
/ 13 июля 2010

Когда мы вычитаем указатель из другого указателя, разница не равна количеству байтов, которые они разделяют, но равна количеству целых чисел (если они указывают на целые числа), которые они разделяют. Почему так?

Ответы [ 8 ]

71 голосов
/ 13 июля 2010

Идея в том, что вы указываете на блоки памяти

+----+----+----+----+----+----+
| 06 | 07 | 08 | 09 | 10 | 11 | mem
+----+----+----+----+----+----+
| 18 | 24 | 17 | 53 | -7 | 14 | data
+----+----+----+----+----+----+

Если у вас есть int* p = &(array[5]), то *p будет 14. Если p=p-3, то *p будет 17.

Так что, если у вас есть int* p = &(array[5]) и int *q = &(array[3]), тогда p-q должно быть 2, потому что указатели указывают на память, расположенную на расстоянии 2 блоков.

При работе с необработанной памятью (массивами, списками, картами и т. Д.) Нарисуйте много ящиков! Это действительно помогает!

35 голосов
/ 13 июля 2010

Потому что все в стране указателей связано со смещением. Когда вы говорите:

int array[10];
array[7] = 42;

То, что вы на самом деле говорите во второй строке:

*( &array[0] + 7 ) = 42;

Буквально переводится как:

* = "what's at"
(
  & = "the address of"
  array[0] = "the first slot in array"
  plus 7
)
set that thing to 42

И если мы можем добавить 7, чтобы сместить точку в нужном месте, мы должны иметь возможность установить противоположное, иначе у нас не будет симметрии в нашей математике. Если:

&array[0] + 7 == &array[7]

Тогда для здравомыслия и симметрии:

&array[7] - &array[0] == 7
10 голосов
/ 13 июля 2010

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

7 голосов
/ 13 июля 2010

Скажем, у вас есть массив из 10 целых чисел:

int intArray[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

Затем вы берете указатель на intArray:

int *p = intArray;

Затем вы увеличиваете p:

p++;

То, что вы ожидаете, потому что p начинается с intArray[0], для увеличенного значения p будет intArray[1].Вот почему указательная арифметика работает так. См. Код здесь.

3 голосов
/ 13 июля 2010

"Когда вы вычитаете два указателя, если они указывают на один и тот же массив, результатом будет количество элементов, разделяющих их"

Проверьте больше здесь .

2 голосов
/ 26 ноября 2014

Этот способ вычитания указателя согласуется с поведением сложения указателя.Это означает, что p1 + (p2 - p1) == p2 (где p1 и p2 - указатели на один и тот же массив).

Добавление указателя (добавление целого числа к указателю) ведет себя аналогичным образом: p1 + 1 дает вамадрес следующего элемента в массиве, а не следующего байта в массиве - что было бы довольно бесполезным и небезопасным делом.

Язык мог бы быть спроектирован так, чтобы указатели добавлялись и вычиталисьТо же самое, что и целые числа, но это означало бы написание арифметики с указателями по-разному и необходимость учета размера указанного типа:

  • p2 = p1 + n * sizeof(*p1) вместо p2 = p1 + n
  • n = (p2 - p1) / sizeof(*p1) вместо n = p2 - p1

Таким образом, результатом будет более длинный и трудный для чтения код, в котором будет легче делать ошибки.

1 голос
/ 13 июля 2010

При применении арифметических операций к указателям определенного типа вы всегда хотите, чтобы результирующий указатель указывал на «действительный» (то есть размер правильного шага) адрес памяти относительно исходной начальной точки.Это очень удобный способ доступа к данным в памяти независимо от базовой архитектуры.

Если вы хотите использовать другой «размер шага», вы всегда можете привести указатель к нужному типу:

int a = 5;
int* pointer_int = &a;
double* pointer_double = (double*)pointer_int; /* totally useless in that case, but it works */
0 голосов
/ 14 июля 2010

@ fahad Арифметика указателя идет в зависимости от размера типа данных, на который он указывает. Поэтому, когда указатель ur имеет тип int, вы должны ожидать арифметику указателя размером int (4 байта). Аналогично для указателя на символ все операции над указателем будет в единицах 1 байт.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...