Операции указателя и приоритет оператора в C
Фон
Просто пообщался с парнем C сегодня, и мы не согласились на следующее:
int intgA[2] = { 1, 2 };
int intgB[2] = { 3, 5 };
int *intAPtr = intgA;
int *intBPtr = intgB;
Итак, когда мы делаем:
*intAPtr++ = *intBPtr++;
Мой анализ
Во-первых:
intBPtr
увеличивается на единицу, указывая теперь на адрес 5.
Тогда, уважение, держащее значение 5;
intAPtr
также увеличивается на единицу, теперь указывая на адрес 2.
Впоследствии ссылка и значение равно 2;
Наконец:
2 заменяется на 5.
Итак, соответственно: 5 и 5.
Его анализ
Значение *intBPtr
сначала присваивается *intAPtr
.
Следовательно, они становятся: 3 и 3.
Затем оба *intAPtr
и *intBPtr
увеличиваются на единицу.
Таким образом, соответственно они становятся: 4 и 4.
Мое предположение
Я думал, что оператор ++
имеет приоритет как над *
, так и =
, поэтому мое утверждение.
Например, если бы мы имели:
*intAPtr++;
Результат должен быть 2, верно? Поскольку мы сначала увеличиваем указатель, а затем разыгрываем.
Итак, почему в приведенном выше случае, как он утверждает, мы сначала присваиваем значение intBPtr
значению intAPtr
и увеличиваем значения last?
После того, как вы сделали все предложения, я запустил код в IDE, и результат подтвердил результат @sujin:
Хотя это подтверждает, что я был прав, по крайней мере, с точки зрения приоритета:
То: *intAPtr++ = *intBPtr++;
intAPtr++
имеет более высокий приоритет, что приводит к: intAPtr
увеличивает свой адрес на 1.
Теперь указывая на: адрес 2.
И аналогично:
intBPtr++
также увеличивается на 1 (адрес).
Теперь указывая на: адрес 5.
Затем он *
поворачивается:
Таким образом, оба получают разыменованные (*) соответственно 2 и 5.
Но проблема существует еще потому, что присваивание выше (=
), похоже, не произошло.
Если бы это было так, то получилось бы 5.
Ждем дальнейшего просвещения.
Ответы
Ответ 1
Утверждение
*intAPtr++ = *intBPtr++;
анализируется как
*(intAPtr++) = *(intBPtr++);
и разбивается следующим образом:
- Значение, указанное в настоящее время на
intBPtr
(3), присваивается местоположению, на которое указывает intAPtr
(intgA[0]
);
- Указатели
intAPtr
и intBPtr
увеличиваются.
Точный порядок, в котором происходят эти вещи, не указан; вы не можете полагаться на intBPtr
, увеличивающийся после intAPtr
или наоборот, и вы не можете полагаться на назначение, которое происходит до приращений и т.д.
Итак, к тому времени, когда все это будет сделано, intgA[0] == 3
и intAPtr == &intgA[1]
и intBPtr == &intgB[1]
.
Выражение a++
оценивается значением a
до приращения.
Ответ 2
Ты и другой парень оба ошибаетесь!
Либо,
1. оба указателя увеличиваются сначала, а затем выполняется присвоение или
2. один указатель увеличивается, затем выполняется назначение, затем увеличивается другой указатель или
3. Первое присваивание происходит, а затем указатели увеличиваются.
Но правило состоит в том, что все побочные эффекты одного оператора должны быть полными до начала следующего утверждения. Имейте в виду, что должны использоваться исходные значения. Пока используется исходное значение, приращение может произойти в любое время.
C-faq: 3.2:
не гарантируется, что приращение или декремент выполняются сразу же после отказа от предыдущего значения и перед оценкой любой другой части выражения. Просто гарантируется, что обновление будет выполняться когда-нибудь, прежде чем выражение будет считаться "завершенным" .
Подробнее читайте , предоставленный Эрик Липперт.
Ответ 3
Да, ++
привязывается более жестко, чем *
, но вы неправильно поняли, как это работает. var++
увеличивает var
, но до приращения вычисляет значение var
. Вы можете придумать это как синтаксический сахар для (var += 1, var - 1)
, если хотите.
Еще один способ подумать об этом: если бы он работал так, как вы думали, то не было бы никакой разницы между var++
и ++var
, и один из них не был бы включен в язык в первое место. C почти не имеет избыточности.
(Приоритет привязки имеет значение, например, означает, что *var++
увеличивает значение переменной var
, тогда как (*var)++
увеличивает значение в ячейке памяти в *var
.)
Ответ 4
Основной эффект оператора ++
заключается в создании значения его операнда (без его увеличения). Побочным эффектом является увеличение операнда.
Даже если побочный эффект выполняется до того, как значение, полученное основным эффектом, используется в другой операции, значение, создаваемое основным эффектом, является исходным значением операнда, а не обновленным значением.
В *x++
, который анализируется как *(x++)
, оператор *
применяется к значению, создаваемому основным эффектом, поэтому операция *
такая же, как если бы оценивалась *x
. Приращение происходит "сбоку", вне оценки основного выражения, поэтому он не принимает участия в определении значения *x++
.
Ответ 5
Пример кода (в linux):
#include <stdio.h>
#include <stdlib.h>
int main() {
int intgA[2] = { 1, 2 };
int intgB[2] = { 3, 5 };
int *intAPtr = intgA; //1
int *intBPtr = intgB; //3
*intAPtr++ = *intBPtr++;
// *intAPtr = *intBPtr;
// *intAPtr++ = 25;
printf("op: %d %d\n", *intAPtr, *intBPtr);
return 0;
}
выход:
op: 2 5
сначала присваивая intBPtr
- intAPtr
, тогда происходит приращение, потому что это пост-приращение.
Ответ 6
Я согласен с ответом Джона Боде, чтобы немного упростить его
Я просто напишу его в коде:
*intAptr = * intBPtr;
равно:
*intAptr =*intBPtr
intAPtr+=1;
inrBPtr+=1;
так что мы получаем:
intAPtr
указывает на 2
intBPtr
указывает на 5