Разница между двумя переменными указателя [duplicate]

этот вопрос уже есть ответ здесь:

Я уже задал этот вопрос в письменном тесте. при запуске приведенного ниже кода на моем lapi я получаю 10 в качестве вывода

#include<stdio.h>
int main()
{
  int *i, *j;/* two pointer variable*/
  i = (int *)60;
  j = (int *)20;
  printf("%d n",i-j);
  return 0;
}

выход :

10 

может кто-нибудь сказать мне, почему выходной is 10.

6 ответов


согласно стандарту C (6.5.6 аддитивные операторы)

9 Когда вычитаются два указателя,оба указывают на элементы тот же объект массива или один за последним элементом массива объект; результатом является разница индексов двух элемент массива.

так что ваша программа имеет неопределенное поведение, потому что указатели не указывают на элементы одного массива.

тем не менее кажется, что компилятор просто генерирует объектный код для вычитания двух указателей, независимо от того, что указатели указывают на элементы одного массива (он тебе доверяет).

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

в вашем случае sizeof( int ) равна 4. Таким образом, память размером 40 байт может вместить 10 элементы тип int, при условии, что sizeof( int ) равна 4.

это значение, равное 10, опережает функцию printf.


вы оцениваете разницу, или "расстояние" между двумя указателями на int. sizeof(int) 4 на вашей платформе. Разница между 60 и 20 составляет 40, то есть расстояние между 10 интами. Ваша реализация, похоже, просто оценивает эту разницу.

однако стандарт C накладывает ограничение на оценку разницы между двумя указателями: оба указателя должны указывать на элементы в массиве или один за концом. Если вы можете обеспечить оба i и j удовлетворите этому, тогда оценка разницы действительна. Поскольку ваш код не обязательно удовлетворяет этому условию, он может иметь неопределено поведение, в этом случае результат/результат мог быть любым.

также обратите внимание, что это неопределенное поведение для де-ссылки i и j если они не указывают на действительные адреса, удерживающие int значения.


разность двух указателей определяется стандартом C только в том случае, если оба указателя указывают на один и тот же объект (массив) (или один позади), поэтому код OP вызывает неопределенное поведение. Результат может быть любым.

из стандарта C11:

6.5.6/9 аддитивные операторы

когда вычитаются два указателя, оба должны указывать на элементы одного и того же объекта массива, или один после последнего элемента массива объекта; результат разница индексы двух элементов массива. Размер результата определяется реализацией, и его тип (целочисленный тип со знаком) -ptrdiff_t определена в <stddef.h> заголовок. Если результат не представляется в объекте этого типа, поведение не определено.

действителен следующий код:

#include <stdio.h>

int main()
{
  int a[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

  int * i = a + 0;
  int * j = a + 10; /* Points "one past the last element" of the array. */

  printf("%td \n", i - j);

  return 0;
}

Он также выводит 10.


принимая разницу между указателями, которые не указывают внутри одного и того же объекта, является неопределенным поведением.

ваши указатели не указывают на какой-либо объект вообще.

это неопределенное поведение для вычитания указателей в вашем коде.

любой результат (10, 40, 65535, -1) является ошибочным.


то, что вы видите, является неопределенным поведением.

указатель должен указывать на действительный адрес памяти и 60 и 20 не.

просто процитировать из стандарта

оба указателя должны указывать на элементы одного и того же объекта массива или на один последний элемент объекта массива, поскольку это не то, что вы видите в своем коде, это UB.


пока это строго неопределено поведение и разрешено случиться, однако компиляторы редко произвольны в их обработке такого кода, и результат может быть объяснен в этом случае как:

    (i - j) == ((60 - 20) / sizeof(int))

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