Путаница вычитания указателя

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

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

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

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

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

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

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

 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 целых чисел:

 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] . Вот почему арифметика указателей работает так. Смотрите код здесь.

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

Подробнее смотрите здесь .

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

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

 int a = 5; int* pointer_int = &a; double* pointer_double = (double*)pointer_int; /* totally useless in that case, but it works */ 

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

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

C может быть сконструирован таким образом, чтобы указатели добавлялись и вычитались так же, как целые числа, но это означало бы:

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

Это приведет к тому, что код будет длиннее, сложнее для чтения и менее безопасен.

*: считая, что разница между p1 и p2 является точным кратным типа, на который они указывают. Если они находятся в одном массиве памяти, это будет верно. Если это не так, то мало смысла делать арифметику указателей на них.

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

  • Плакат с 8 этапами перевода на языке C
  • Приведение float в int (побитовое) в C
  • Квадрат числа определяется с помощью #define
  • Как преобразовать целое число в шестнадцатеричную строку в C?
  • Как обменяться между различными .c файлами?
  • Как отсортировать массив структур в C?
  • Является ли модификация строковых литералов неопределенным поведением в соответствии со стандартом C89?
  • Правильный способ утилиты Image / Bitmap и PictureBox
  • Насколько неопределенным является неопределенное поведение?
  • Разбор аргументов командной строки?
  • Почему я не должен использовать atoi ()?
  • Давайте будем гением компьютера.