Постинкремент в цикле while - PullRequest
       12

Постинкремент в цикле while

6 голосов
/ 31 августа 2011

Следующий код немного смутил меня:

char * strcpy(char * p, const char * q) {
  while (*p++=*q++);
  //return
}

Это упрощенная реализация функции strcpy. Из этого кода мы видим, что указатели p и q увеличиваются, затем разыменовываются, и q присваивается p до тех пор, пока не будет достигнут символ \0.

Я бы хотел, чтобы кто-то объяснил первую итерацию цикла while.

Ответы [ 8 ]

9 голосов
/ 31 августа 2011

Поскольку ++ находится после переменных, они не увеличиваются до тех пор, пока после не будет вычислено выражение.Вот почему это пост-инкрементный оператор;предварительное увеличение имеет префикс (++p).*++p пишет во второе место, *p++ пишет в первое.

2 голосов
/ 31 августа 2011

Выражения x++ и ++x имеют как результат (значение), так и побочный эффект .

Результат выражения x++ является текущим значением x. Побочный эффект заключается в том, что содержимое x увеличивается на 1.

Результат выражения ++x является текущим значением x plus 1. Побочный эффект такой же, как указано выше.

Обратите внимание, что побочный эффект не нужно применять сразу после вычисления выражения; это должно только быть применено перед следующей точкой последовательности. Например, учитывая код

x = 1;
y = 2;
z = ++x + y++;

нет никакой гарантии, что содержимое x будет изменено до вычисления выражения y++ или даже до того, как результат ++x + y++ будет присвоен z (ни =, ни + операторы вводят точку последовательности). Выражение ++x оценивается как 2, но возможно, что переменная x может не содержать значение 2 до тех пор, пока не будет присвоено z.

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

Операторы Postfix имеют более высокий приоритет, чем унарные операторы, поэтому такие выражения, как *p++, анализируются как *(p++) (т.е. вы применяете оператор * к результату выражения p++). Опять же, результатом выражения p++ является текущее значение p, поэтому while (*p++=*q++); не пропускает первый элемент.

Обратите внимание, что операндом операторов автоинкремента / декремента должно быть lvalue (по сути, выражение, которое относится к ячейке памяти, так что память может быть прочитана или изменена). Результат выражения x++ или ++x равен , а не lvalue, поэтому вы не можете писать такие вещи, как ++x++ или (x++)++ или ++(++x). Вы могли бы написать что-то вроде ++(*p++) (p++ не lvalue, но *p++ is), хотя это, вероятно, даст вам пощечину любому, кто читает ваш код.

2 голосов
/ 31 августа 2011

Нет, приращение происходит после назначения.

Если бы это было *(++p), указатель p был бы увеличен и после этого назначен.

2 голосов
/ 31 августа 2011

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

Ваше рассуждение было бы правильным, если бы цикл while был написан следующим образом:

while (*++p=*++q);

В этом случае приращение происходит до разыменования.

1 голос
/ 31 августа 2011

Состояние цикла while выполняется после приращения.Эквивалентно:

while (true) {
    char* old_p = p;
    const char* old_q = q;

    ++p; // or p++;
    ++q; // or q++;

    *old_p = *old_q;
    if (*old_p == '\0')
        break;
}
1 голос
/ 31 августа 2011

Значение q++ равно q
Значение ++q равно q+1

1 голос
/ 31 августа 2011

Это расширенная реализация функции strcpy. Из этого кода мы видим, что указатели p и q увеличиваются, чем разыменовываются, и q присваивается p до тех пор, пока не будет достигнуто \ 0 char.

Это происходит наоборот. Значение в *p устанавливается в *q, тогда оба указателя увеличиваются.

Если у вас есть int foo = bar++, приращение происходит после того, как foo был установлен. Чтобы это произошло первым, вы должны сделать int foo = ++bar

1 голос
/ 31 августа 2011

Правая часть выражения (* q ++) будет оцениваться до * p ++, и оба будут увеличиваться только после того, как присвоение произойдет.

Прочитайте оператор справа налево и запомните, что постинкремент (q ++ вместо ++ q) происходит после того, как все остальное в строке разрешено.

*q --> dereference q
=  --> assign the value
*p --> to p

увеличить оба.

Делайте это до тех пор, пока q p не примет элемент q = 0, то есть когда он достигнет нулевого терминатора.

...