2016-11-21 13 views
0
int main(void) { 
    int *a; 
    int *b = a++; 
    printf("%d\n",b-a); 
    return 0; 
} 

Я ожидал, что выход будет 1, почему это -1?Разница указателей между 2 int указателями

Предположим, что в приведенном выше вопросе вместо a++ У меня есть ++a.

Это еще неопределенное поведение?

+0

Что у вас? –

+9

Поскольку 'b = a ++' присваивает 'a'' b', а затем увеличивает 'a' (что не влияет на' b'). – Cairnarvon

+0

Подсказка: 'printf ("% d \ n ", b-a);'? Cm'on, вы знаете, остальные, :) –

ответ

0

Когда вы увеличиваете указатель, он не добавляет значение в 1. Он просто указывает указателю указать на следующее местоположение. Кроме того, ваши указатели никогда не были инициализированы, и они просто указывают на случайные числа мусора.

4

Первая проблема, как я вижу здесь, в первую очередь с

int *a; 

a автоматическая локальная, а начальное значение является неопределенным (без явной инициализации), следовательно, делает a++ (или, ++a, для этого вопроса) вызывает undefined behavior.

Это указано, относительно вычитания указателя, см. Этот ответ на why we need the operands of subtraction operator to be address of elements from same array object.

Наконец, вычитания двух указателей производят тип ptrdiff_t, вы должны использовать %td для печати результата. В противном случае вы снова вызываете UB.


[Как уже упоминалось в комментариях ниже]

Предполагая, что указатели инициализируются правильно, что-то вроде

int k[5] = {0}; 
int * a = &(k[0]); 
int *b = a++; 
printf("%td\n",b-a); 

в этом случае результат будет -1, так как это разница в индексе обоих элементов (помните, a++ - post-increment).

Глава §6.5.6/9, C11 стандарт

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

+0

Я * не * нисходящий. Просто хотел спросить, почему здесь 'a ++' UB? AFAIK, здесь 'a' является указателем (и уже помещен в стек), а' a ++ 'увеличит адрес, хранящийся в' a', на 4 или 8 или что-то еще. Я думаю, что '(* a) ++' будет UB. Пожалуйста, скажи мне, что мне не хватает. – babon

+0

@babon вы сбиваете с толку 'a' с' & a'? 'a ++' - это UB, основанный на той же логике, если 'a' также был бы« int ». –

+0

И каков был бы результат, если указатель был правильно инициализирован? OP ожидает 1 ... –

2

Разность двух указателей ((Б-А) в данном случае) не определена в C, если только два указателя, не указывают на адреса одного и того же массива.

Кроме того, поскольку указателю «a» в вашем коде не присвоен ни один адрес (содержит значение мусора), то любая операция является грехом.

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

+4

'... указывают на адреса одного и того же массива' + 'или один за последним элементом массива' – 4386427

+0

И каков будет результат, если указатель был правильно инициализирован? ОП ожидает 1 ... –

+0

@Bob__ Как правило, мы делаем (b-a), чтобы получить количество элементов массива между этими двумя указателями. но из-за int * b = a ++; результат будет -1, что бесполезно –

0

int *a - переменная с автоматическим хранением и не имеет своего адреса (&a). Поэтому код вызывает неопределенное поведение (согласно 6.3.2.1, see this), и ваша программа не может иметь прогнозируемого результата.

Использование спецификатора формата %d на ptrdiff_t также вызывает неопределенное поведение (7.21.6.1/9). Вы должны использовать %td для ptrdiff_t и %p для указателей.

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

4

Прежде всего, ваш код вызывает неопределенное поведение, поскольку он считывает и изменяет неинициализированные переменные.

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

Давайте предположим, что указатель фактически указывает на действительный объект:

int i; 
int *a = &i; 
int *b = a++; 
printf("%td\n",b-a); 

Постфиксная ++ оператор дает текущее значение операнда, а затем увеличивает значение операнда на единицу. Выше код идентичен:

int i; 
int *a = &i+1; 
int *b = &i; 
printf("%td\n",b-a); 

Указатель а указывает на один-мимо объекта I, и указатель б указывает на объект я. Вычитание из-за арифметики указателя даст -1. Если операция была: a-b, тогда результат будет равен 1.

Это определено поведение. не

-1

Это не Undefine поведение

когда вы объявили * а, а указывает на ячейку памяти, *b = a++; b указать то же место, что и a, AND. a указать точку 1, которая больше, чем предыдущее местоположение, на которое указывает b.

b - a = -1 // правильно

я дам пример

int main(void) 
    { 
     int *a; // 0x408 
     int *w = a++; // 0x400 
     int *b = a++; // 0x404 

     int c = (b-a); 
     printf("%d\n",b-a);// -1 
     printf("%d\n",w-a); // -2 

     return 0; 
    } 

я intruduce w лучше ilustrate

Адрес памяти во время выполнения этой переменной будет выглядеть примерно так выше.

b - a (0x404 - 0x408) == -1 (-4);

sizeof int (в данном случае) - 4 байта.и указатели, держащие адрес междунар будет иметь изменение их адрес (+/-) на коэффициент 4, , насколько это ИНТ беспокойство в этом случае 4 байта содержат один целое число (1 единица)

w - a == (0x400 - 0x408) = -2(-8)

если у вас есть

a - w == (0x408 - 0x400) = 2(8)

 Смежные вопросы

  • Нет связанных вопросов^_^