#c #pointers #operators
#c #указатели #операторы
Вопрос:
Каков порядок вычисления в *ptr
? Меняется ли это, когда в операции задействованы указатели и значения lvalues?
Если приоритет a
выше, чем *a
или a
, то почему *a
сначала вычисляется возврат увеличенного значения с последующим изменением указателя, а не изменение указателя с последующим увеличением значения в местоположении. Ссылка на приоритет:https://en.cppreference.com/w/cpp/language/operator_precedence
arr = {9, 99, 999 };
int *ptr = arr;
std::cout << *ptr << 't';
std::cout << *ptr;
Я ожидал, что результат будет 100 100, но фактический результат был 10 99.
Комментарии:
1. Вместо бесконечного анализа нечитаемого кода, напишите читаемый код. <g>
Ответ №1:
Приращение постфикса a
увеличивает указатель ptr, но возвращает копию ptr перед операцией (см. Разницу между префиксом / постфиксом). Таким образом, его можно переписать (как указано в ответе Квимби) как (*(ptr )) и выглядит следующим образом:
- ptr : увеличивает ptr так, чтобы он указывал на 99, но возвращает другой указатель, который по-прежнему указывает на 9
- * ptr : разыменования, вычисляется как 9
- *ptr : увеличивает значение, на которое указывает скопированный указатель, то есть увеличивает на 9 и возвращает 10
Здесь хорошо объясняется логика, лежащая в основе предварительного / последующего увеличения / уменьшения:
Операторы предварительного увеличения и предварительного уменьшения увеличивают или декрементируют значение объекта и возвращают ссылку на результат. Постинкрементное и пострекрементное уменьшение создает копию объекта, увеличивает или уменьшает значение объекта и возвращает копию, полученную до увеличения или уменьшения.
Из:https://en.cppreference.com/w/cpp/language/operator_incdec
Комментарии:
1. Итак, если бы мы скажем, перегрузили операторы предварительного и постинкрементного увеличения для класса, скажем, A, и создали конструктор копирования A, тогда приращение post выдало бы ошибку?
2. с чего бы это? Когда вы пишете оператор для пользовательского типа, он будет использоваться только при вашем вызове. Кстати, я рекомендую попробовать это самостоятельно, а не верить мне 🙂
Ответ №2:
Постфиксные операторы имеют более высокий приоритет, чем префикс, поэтому они более жестко привязываются / first so: *ptr
совпадает с (*(ptr ))
, который сводится к тому, какой операнд над чем работает. Таким образом, postfix будет применен к вашему указателю ‘ptr’, но ‘после’ первой строки std::cout . Префикс будет работать с разыменованным ptr, так что это все то же самое, что:
int arr[] = {9, 99, 999 };
int *ptr = arr;
(*ptr); // 9 1=10
std::cout << *ptr << 't';
ptr ; // now ptr points to 99
std::cout << *ptr;
Ответ №3:
Короче говоря, потому что *ptr
переписывается как (*(ptr ))
Правила в ссылке довольно ясны:
- Постфикс имеет наивысший приоритет =>
*(ptr )
- Префиксы и * имеют одинаковый приоритет, и они являются правоассоциативными =>
(*(ptr ))
Выражение также можно разделить на отдельные операторы, подобные этому:
arr = {9, 99, 999 };
int *ptr = arr;
int *ptr2 = ptr ;//ptr2 still points to the first element
int val = *ptr2; // 9
int incVal= val; // 10
Надеюсь, ясно, что ptr
теперь указывает на второй элемент массива, а результатом выражения является увеличенное значение.
Ответ №4:
Поскольку вы используете одномерный массив
*ptr
ссылается на приращение в указателе ptr к 0 элементам массива, после приращения результат для этого будет равен 10
Постфикс
имеет наивысший приоритет => *(ptr )