Не могу понять одну странность с приоритетом операторов в C++
void mass(int* der, int* a)
{
cout << der << endl; //der = 0009D870
*der = 5;
cout << der << endl; //der = 0009D870
*(der++) = 9; //тут проблема
cout << der << endl; //der = 0009D874 (инкрементируется также и при записи *++der)
}
void main()
{
int* der = new int[2];
der[0] = 3;
der[1] = 3;
mass(der, &der[1]);
cout « der[0] « '\n' « der[1];
}
Если записать так: *(der++), то сначала происходит разыменование, а потом инкремент, несмотря на скобки. Значение элемента der[0] меняется на 5, а потом на 9. Если записать так: *++der, то происходит сначала инкремент, потом разыменование, значение элемента массива der[0] меняется на 5, а der[1] на 9. Почему так происходит?
Приоритет операций в языках С и С++ не имеет прямого отношения к порядку их выполнения. Приоритет операций описывает лишь группировку между операторами и операндами во внешне неоднозначных случаях, т.е. отвечает на вопрос о том, какой оператор относится к какому оператору.
(Формально в С и С++ нет никакого "приоритета операций", а есть только грамматика, которая и задает такую группировку. Так называемый приоритет операций - это лишь упрощенный и более удобный способ запоминания этой группировки.)
Вы также наделяете термин выполняется некоей атомарностью, которой у него на самом нет. У каждого оператора, у каждого подвыражения в С и С++ обычно есть результат и потенциально есть побочные эффекты. Вычисление результата оператора (value computation) - это одна часть процесса выполнения оператора, а материализация его побочных эффектов - это другая часть процесса его выполнения. Эти части выполняются в общем случае независимо друг от друга, в совершено разные моменты времени. То есть выполнение оператора в полном объеме может быть "размазано" по всему процессу вычисления полного выражения.
Если записать так: *(der++), то сначала происходит разыменование, а потом инкремент, несмотря на скобки.
Здесь написана какая-то ерунда. Никакого "сначала происходит разыменование" тут нет и быть не может.
Из-за скобок никакой внешней неоднозначности тут нет: ++
относится к der
, а *
относится к результату ++
. Сначала вычисляется именно результат ++
. Так как это постфиксный ++
, его результатом должно быть старое значение der
. Что вы и наблюдаете.
И совершенно не важно, произошло ли уже изменение значения переменной der
в момент применения оператора *
. Может произошло, а может нет. Главное, что ++
в качестве результата вернул старое значение и именно старое значение попало на вход оператору *
. Это все, что вас должно беспокоить: *
применяется к старому значению der
. Всякие "сначала" и "потом" вас беспокоить не должны вообще.
Скобки тут ни на что не влияют. Их можно убрать и тогда для правильного понимания внешне неоднозначного выражения придется применить приоритеты. Так как постфиксные операторы всегда обладают бОльшим приоритетом, чем префиксные, выражение *der++
разбирается как *(der++)
.
Если записать так: *++der, то происходит сначала инкремент, потом разыменование
В этом выражении неоднозначности нет и приоритеты никакой роли не играют вообще. ++
относится к der
, а *
применен к результату ++
.
Опять же, важно тут не то, что выполняется первым, а что вторым, а только то, что результат префиксного ++
- это новое значение der
. То есть *
должен применяться к увеличенному на 1 значению der
.
Здесь, кстати, языки С и С++ формально ведут себя по-разному. Язык С++ гарантирует, что когда оператор *
получает на вход увеличенное значение der
, сама переменная der
тоже уже получила новое значение. А вот язык С такого не гарантирует: оператор *
тоже получает на вход увеличенное значение der
, но вот было ли к этому моменту уже выполнена модификация самой перменной der
- не оговаривается.
int a[3]{};
int* der = a; //der содержит адрес первого элемента массива
int* p = der++;
указатель p
тоже содержит адрес первого элемента, но der
уже(сразу после выражения) указывает на второй элемент
int* q = ++p;
q
указывает на второй элемент, т.е. q == der
, так что тут скобки роли не играют, дело в результате постфиксного и префиксного инкремента
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Наткнулся на интересную особенность при инициализации массива int
Есть одноплатный компьютер для него написал код с графикой использую qtКод писался на Windows как перенести его на Linux, SDK qt на Linux установил но как...
Предположим, что у меня есть поток для записи в файл ofstream
Проблема заключается в том, что код спокойно выполняется на онлайн gcc компиляторах и MSVS, а у меня - нетОшибку видит в строках while (string[i] != '\0') и ошибкуerror:...