Арифметика указателей: ++ * ptr или * ptr ++? - PullRequest
20 голосов
/ 06 марта 2011

Я изучаю язык Си и довольно запутался в различиях между ++*ptr и *ptr++.

Например:

int x = 19;
int *ptr = &x;

Я знаю, ++*ptr и *ptr++ дают разные результаты, но я не уверен, почему это так?

Ответы [ 3 ]

47 голосов
/ 06 марта 2011

Эти операторы дают разные результаты из-за способа, которым операторы связываются. В частности, префиксный оператор ++ имеет тот же приоритет, что и *, и они связываются справа налево. Таким образом

++*ptr

анализируется как

++(*ptr)

означает «увеличить значение, на которое указывает ptr,». С другой стороны, оператор postfix ++ имеет более высокий приоритет, чем оператор разыменования *. Thefore

*ptr++

означает

*(ptr++)

, что означает «оценить значение, на которое в данный момент указывает ptr, и увеличить значение ptr» (порядок которого не указан).

В контексте, который вы описали, вы, вероятно, захотите написать ++*ptr, который будет косвенно увеличивать x до ptr. Запись *ptr++ была бы опасна, потому что она шла бы на ptr вперед за x, а поскольку x не является частью массива, указатель будет зависать где-то в памяти (возможно, над самой собой!)

Надеюсь, это поможет!

8 голосов
/ 29 апреля 2016

Принятый ответ неверен. Это не тот случай, когда оператор постфикса ++ имеет тот же приоритет, что и разыменование / косвенное указание *. Префиксный и постфиксный операторы имеют разный приоритет, и только оператор prefix имеет тот же приоритет, что и разыменование / косвенность.

Как показывает таблица приоритетов , постфикс ++ имеет более высокий приоритет , чем разыменование / косвенность *. Таким образом, *ptr++ оценивается как *(ptr++). ptr++ соответствует текущему значению ptr; увеличивается ptr только как побочный эффект. Значение выражения совпадает с текущим значением ptr. Так что это не повлияет на значение, хранящееся в указателе. Он просто разыменует указатель (то есть получает текущее значение, хранящееся там, которое составляет 19), а затем перемещает указатель. В вашем примере нет определенного значения, сохраненного в новой позиции ptr, поэтому указатель указывает на мусор. Разыменование это сейчас было бы опасно.

Также, как показано в таблице, префикс ++ имеет тот же приоритет, что и разыменование / косвенное указание *, но из-за ассоциативности справа налево он оценивается как ++(*ptr). Сначала будет разыменован указатель (то есть получено значение, сохраненное по указанному адресу), а затем увеличено это значение. Т.е. значение теперь будет 20.

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

4 голосов
/ 06 марта 2011

Как говорит templatetypedef, вы должны указать круглые скобки около *ptr, чтобы обеспечить результат. Например, следующее дает 1606415888, используя GCC и 0, используя CLang на моем компьютере:

int x = 19;
int *ptr = &x;
printf("%d\n", *ptr++);
printf("%d\n", *ptr);

А вы ожидали, что x будет 20. Поэтому используйте (*ptr)++ вместо.

...