Если вы не используете круглые скобки для указания порядка операций, приращения префикса и постфикса имеют приоритет над ссылкой и разыменованием. Однако приращение префикса и приращение постфикса - это разные операции. В ++ x оператор берет ссылку на вашу переменную, добавляет ее к ней и возвращает по значению. В x ++ оператор увеличивает вашу переменную, но возвращает ее старое значение. Они ведут себя примерно так (представьте, что они объявлены как методы внутри вашего класса):
//prefix increment (++x)
auto operator++()
{
(*this) = (*this) + 1;
return (*this);
}
//postfix increment (x++)
auto operator++(int) //unfortunatelly, the "int" is how they differentiate
{
auto temp = (*this);
(*this) = (*this) + 1; //same as ++(*this);
return temp;
}
(Обратите внимание, что в приращении постфикса есть копия, что делает его менее эффективным. Вот почему вам следует использовать префикс ++ i вместо циклов i ++ in, хотя большинство компиляторов делают это автоматически для вас. эти дни.)
Как видите, приращение постфикса обрабатывается первым, но из-за его поведения вы будете разыменовывать предыдущее значение указателя.
Вот пример:
char * x = {'a', 'c'};
char y = *x++; //same as *(x++);
char z = *x;
Во второй строке указатель x будет увеличен до разыменования, но разыменование произойдет поверх старого значения x (которое является адресом , возвращаемым приращением постфикса). Таким образом, у будет инициализирован с «а», а z с «с». Но если вы сделаете это так:
char * x = {'a', 'c'};
char y = (*x)++;
char z = *x;
Здесь x будет разыменовываться, а значение , указанное им ('a'), будет увеличиваться (до 'b'). Поскольку приращение постфикса возвращает старое значение, y все равно будет инициализироваться с помощью «a». И поскольку указатель не изменился, z будет инициализирован с новым значением 'b'.
Теперь давайте проверим префиксы:
char * x = {'a', 'c'};
char y = *++x; //same as *(++x)
char z = *x;
Здесь разыменование происходит при увеличении значения x (которое немедленно возвращается префиксным оператором приращения), поэтому и y, и z будут инициализированы с помощью «c». Чтобы получить другое поведение, вы можете изменить порядок операторов:
char * x = {'a', 'c'};
char y = ++*x; //same as ++(*x)
char z = *x;
Здесь вы гарантируете, что сначала увеличиваете содержимое x, а значение указателя никогда не изменяется, поэтому y и z будут назначены с помощью 'b'. В функции strcpy (упомянутой в другом ответе), приращение также выполняется первым:
char * strcpy(char * dst, char * src)
{
char * aux = dst;
while(*dst++ = *src++);
return aux;
}
На каждой итерации сначала обрабатывается src ++ и, будучи постфиксным приращением, возвращает старое значение src. Затем старое значение src (которое является указателем) разыменовывается для присвоения тому, что находится слева от оператора присваивания. Затем значение dst увеличивается, и его старое значение разыменовывается, чтобы стать lvalue и получить старое значение src. Вот почему dst [0] = src [0], dst [1] = src [1] и т. Д. До тех пор, пока * dst не будет присвоено 0, что приведет к разрыву цикла.
Добавление:
Весь код в этом ответе был протестирован на языке Си. В C ++ вы, вероятно, не сможете инициализировать указатель списком. Итак, если вы хотите проверить примеры в C ++, вы должны сначала инициализировать массив, а затем уменьшить его до указателя:
char w[] = {'a', 'c'};
char * x = w;
char y = *x++; //or the other cases
char z = *x;