Как работает унарное сложение на C-указателях? - PullRequest
4 голосов
/ 15 февраля 2011

Я знаю, что унарный оператор ++ добавляет один к числу.Тем не менее, я обнаружил, что если я делаю это по указателю int, он увеличивается на 4 (размер int в моей системе).Почему он это делает?Например, следующий код:

int main(void)
{
  int *a = malloc(5 * sizeof(int));
  a[0] = 42;
  a[1] = 42;
  a[2] = 42;
  a[3] = 42;
  a[4] = 42;
  printf("%p\n", a);
  printf("%p\n", ++a);
  printf("%p\n", ++a);
  return 0;
}

вернет три числа с разницей 4 между ними.

Ответы [ 9 ]

6 голосов
/ 15 февраля 2011

Это просто способ C - полное объяснение приведено в спецификации, Раздел 6.5.6 Аддитивные операторы , параграф 8:

Когда выражение, имеющее целочисленный тип, добавляется к указателю или вычитается из него, результат имеет тип операнда указателя. Если операнд-указатель указывает на элемент объекта массива, и массив достаточно велик, результат указывает на смещение элемента от исходного элемента, так что разность индексов результирующего и исходного элементов массива равна целочисленному выражению. Другими словами, если выражение P указывает на i -й элемент массива, выражения (P)+N (эквивалентно N+(P)) и (P)-N (где N имеет значение n ) указывают соответственно на i + n -й и i - n -й элементов массива, если они существуют. Более того, если выражение P указывает на последний элемент объекта массива, выражение (P)+1 указывает на один элемент после последнего элемента объекта массива, и если выражение Q указывает один за последним элементом объекта массива, выражение (Q)-1 указывает на последний элемент объекта массива. Если и операнд-указатель, и результат указывают на элементы одного и того же объекта массива или один после последнего элемента объекта массива, оценка не должна вызывать переполнение; в противном случае поведение не определено. Если результат указывает на один последний элемент массива, он не должен использоваться в качестве операнда унарного оцениваемого оператора *.

Чтобы связать это с использованием префиксного оператора ++, вам также необходимо прочитать Раздел 6.5.3.1 Операторы увеличения и уменьшения префикса , параграф 2:

Значение операнда префикса ++ увеличивается на единицу. Результатом является новое значение операнда после увеличения. Выражение ++E эквивалентно (E+=1).

А также Раздел 6.5.16.2 Составное назначение , пункт 3:

A составное назначение формы E1 op = E2 отличается от простого выражения присваивания E1 = E1 op (E2) только в том случае, если значение E1 оценивается только один раз.

3 голосов
/ 15 февраля 2011

Увеличивает местоположение указателя на размер int, объявленного типа указателя.

Помните, int * это просто указатель на место в памяти, где вы говорите"int" сохраняется.Когда вы ++ указываете на указатель, он перемещается на одну позицию (на размер шрифта), в этом случае ваше значение будет на «4» выше, поскольку sizeof(int)==4.

2 голосов
/ 15 февраля 2011

Причина этого в том, чтобы сделать следующее утверждение верным:

*(ptr + n) == ptr[n]

Они могут использоваться взаимозаменяемо.

1 голос
/ 15 февраля 2011

Это делается для того, чтобы вы не начали обращаться к целому числу в середине.

1 голос
/ 15 февраля 2011

Потому что в «C» арифметика указателя всегда масштабируется по размеру объекта, на который указывает.Если вы немного подумаете об этом, это окажется «правильным поступком».

1 голос
/ 15 февраля 2011

В арифметике указателей добавление единицы к указателю добавит размер типа, на который он указывает.

так для данного:

TYPE * p;

Добавление к p фактически увеличит на sizeof(TYPE). В этом случае размер int равен 4.

См. этот связанный вопрос

0 голосов
/ 15 февраля 2011

"Зачем это делает?"Почему вы ожидаете, что это сделает что-нибудь еще?Увеличение точки приводит к тому, что она указывает на следующий элемент типа, на который указывает указатель.

0 голосов
/ 15 февраля 2011

Это просто, потому что когда дело доходит до указателя, в вашем случае целочисленный указатель, унарный приращение означает УВЕЛИЧЕНИЕ РАСПОЛОЖЕНИЯ ПАМЯТИ ОДНОМ ЕДИНИЦЕ, где ОДИН ЕДИНИЦА = РАЗМЕР ИНТЕГРИ.

Этот размер целого числа зависит от компиляции до компилятора, для 32-битного и 16-битного - 4 байта, а для 64-битного компилятора - 8 байтов.

Попробуйте выполнить ту же программу с типом символов: он даст разницу в 1 байт, поскольку символ занимает 1 байт.

Короче, разница 4-х в том, что вы столкнулись с разницей РАЗМЕРА ОДНОГО ЦЕЛОГО в памяти.

Надеюсь, это помогло, если нет, я буду рад помочь, просто дайте мне знать.

0 голосов
/ 15 февраля 2011

Потому что указатель не является ссылкой;).Это не значение, это просто адрес в памяти.Когда вы проверяете значение указателя, оно будет числом, возможно большим, не связанным с фактическим значением, которое хранится в этой позиции памяти.Скажем, printf("%p\n", a); печатает «2000000» - это означает, что ваш указатель указывает на 2000000-й байт в памяти вашего устройства.Он практически не знает, какое значение там хранится.

Теперь указатель знает, на какой тип он указывает.Целое число в вашем случае.Поскольку целое число имеет длину 4 байта, когда вы хотите перейти к следующей «ячейке», на которую указывает указатель, оно должно быть 2000004. Это на целое число дальше, поэтому a++ имеет смысл.Кстати, если вы хотите получить 42 (из вашего примера), распечатайте значение, указанное в: printf("%d\n", *a);

Надеюсь, это имеет смысл;)

...