Постинкрементная и прединкрементная концепция?

Я не понимаю концепцию постфикса и префикса увеличения или уменьшения. Кто-нибудь может дать лучшее объяснение?

14 ответов

Решение

Все четыре ответа пока неверны в том смысле, что они утверждают определенный порядок событий.

Полагая, что "городская легенда" привела многих начинающих (и профессиональных) в заблуждение, то есть к бесконечному потоку вопросов о неопределенном поведении в выражениях.

Так.

Для встроенного префиксного оператора C++,

++x

приращений x и производит как результат выражения x как ценность, в то время как

x++

приращений x и выдает в результате выражения исходное значение x,

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

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

int i, x;

i = 2;
x = ++i;
// now i = 3, x = 3

i = 2;
x = i++; 
// now i = 3, x = 2

"Post" означает после - то есть приращение выполняется после чтения переменной. "Pre" означает раньше - поэтому значение переменной сначала увеличивается, а затем используется в выражении.

Разница между приращением постфикса, x++ и приращение префикса, ++x, именно в том, как два оператора оценивают свои операнды. Постфиксное приращение концептуально копирует операнд в память, увеличивает исходный операнд и, наконец, возвращает значение копии. Я думаю, что это лучше всего иллюстрируется реализацией оператора в коде:

int operator ++ (int& n)  // postfix increment
{
    int tmp = n;
    n = n + 1;
    return tmp;
}

Приведенный выше код не будет компилироваться, потому что вы не можете переопределить операторы для примитивных типов. Компилятор также не может сказать, что здесь мы определяем постфиксный оператор, а не префикс, но давайте представим, что это правильный и правильный C++. Вы можете видеть, что постфиксный оператор действительно действует на свой операнд, но он возвращает старое значение до приращения, поэтому результат выражения x++ это значение до приращения. x Однако увеличивается.

Приращение префикса также увеличивает свой операнд, но оно возвращает значение операнда после приращения:

int& operator ++ (int& n)
{
    n = n + 1;
    return n;
}

Это означает, что выражение ++x оценивает значение x после приращения.

Легко думать, что выражение ++x поэтому эквивалентно assignmnet (x=x+1), Однако это не совсем так, потому что приращение - это операция, которая может означать разные вещи в разных контекстах. В случае простого примитивного целого числа, действительно ++x заменяется на (x=x+1), Но в случае типа класса, такого как итератор связанного списка, приращение префикса итератора определенно не означает "добавление единицы к объекту".

Никто не ответил на вопрос:почему эта концепция сбивает с толку?

Как бакалавр компьютерных наук, мне потребовалось некоторое время, чтобы понять это из-за того, как я читаю код.

Следующее не правильно!


х = у ++

X равно y после увеличения. Казалось бы, что логически означает, что X равно значению Y после выполнения операции приращения. Сообщение означает после.

или же

х = ++ у
X равен y предварительному инкременту. Казалось бы, что логически означает, что X равно значению Y до того, как будет выполнена операция приращения. Предварительный смысл раньше.


То, как это работает, на самом деле наоборот. Эта концепция сбивает с толку, потому что язык вводит в заблуждение. В этом случае мы не можем использовать слова для определения поведения.
x = ++ y фактически читается, так как X равно значению Y после приращения.
x = y ++ фактически читается, поскольку X равно значению Y до приращения.

Слова pre и post обратны по отношению к семантике английского языка. Они означают только то, где ++ находится по отношению к Y. Больше ничего.

Лично, если бы у меня был выбор, я бы поменял значения ++ y и y ++. Это всего лишь пример идиомы, которую мне пришлось выучить.

Если есть способ для этого безумия, я хотел бы знать простыми словами.

Спасибо за прочтение.

Это довольно просто. Оба будут увеличивать значение переменной. Следующие две строки равны:

x++;
++x;

Разница в том, что если вы используете значение переменной, которая увеличивается:

x = y++;
x = ++y;

Здесь обе строки увеличивают значение y на единицу. Однако первый присваивает значение y до приращения x, а второй присваивает значение y после приращения x.

Так что есть разница только в том случае, если приращение также используется в качестве выражения. Постинкрементное увеличение увеличивается после возврата значения. Предварительное увеличение увеличивается до.

int i = 1;
int j = 1;

int k = i++; // post increment
int l = ++j; // pre increment

std::cout << k; // prints 1
std::cout << l; // prints 2

Пост приращение подразумевает значение i увеличивается после того, как он был назначен k, Однако предварительное увеличение подразумевает, что значение j увеличивается до того, как оно будет присвоено l,

То же самое относится и к декременту.

Здесь уже есть хорошие ответы, но, как обычно, кажется, что просто не хватает ясности в том, чтобы просто вспомнить, как они работают. Я предполагаю, что это возникает из-за того, что семантическое определение номенклатуры не совсем просто. Например, вы можете знать, что «до» означает «до». Но возвращает ли предварительный приращение ++i значение i перед приращением или оно увеличивает i перед возвратом значения?

Мне гораздо проще визуально следить за выражением слева направо:

              ++                    i 
-------------------------------------------------->
    Increment i   Then supply the value of i


             i                      ++
-------------------------------------------------->
    Supply the value of i    Then increment i

Конечно, как указывает Альф в принятом ответе, это может не отражать, когда обновляется «настоящее я», но это удобный способ думать о том, что передается выражению.

Пост-инкремент:

int x, y, z;

x = 1;
y = x++; //this means: y is assigned the x value first, then increase the value of x by 1. Thus y is 1;
z = x; //the value of x in this line and the rest is 2 because it was increased by 1 in the above line. Thus z is 2.

Предварительное приращение:

int x, y, z;

x = 1;
y = ++x; //this means: increase the value of x by 1 first, then assign the value of x to y. The value of x in this line and the rest is 2. Thus y is 2.
z = x; //the value of x in this line is 2 as stated above. Thus z is 2.

Поскольку теперь у нас есть встроенные фрагменты JavaScript, я мог бы также добавить интерактивный пример увеличения до и после. Это не C++, но концепция остается прежней.

let A = 1;
let B = 1;

console.log('A++ === 2', A++ === 2);
console.log('++B === 2', ++B === 2);

Постинкремент(a++)

Если int b = a++, то это означает

int b = a;

a = a+1;

Здесь мы добавляем 1 к значению. Значение возвращается до увеличения

Например, а = 1; б = а ++;

Тогда б = 1 и а =2

Предварительное увеличение (++a)

Если int b = ++ a; тогда это значит

a=a+1;

int b=a ;

Предварительное увеличение: это добавит 1 к основному значению. Значение будет возвращено после увеличения, для a = 1; b = ++ a; Тогда b=2 и a=2.

Из стандарта C99 (C++ должен быть таким же, за исключением странной перегрузки)

6.5.2.4 Постфиксные операторы увеличения и уменьшения

Ограничения

1 Операнд постфиксного оператора увеличения или уменьшения должен иметь квалифицированный или неквалифицированный вещественный или указательный тип и быть модифицируемым lvalue.

Семантика

2 Результатом оператора postfix ++ является значение операнда. После того, как результат получен, значение операнда увеличивается. (То есть к нему добавляется значение 1 соответствующего типа.) См. Обсуждение аддитивных операторов и составного присваивания для получения информации об ограничениях, типах и преобразованиях, а также о влиянии операций на указатели. Побочный эффект обновления сохраненного значения операнда должен иметь место между предыдущей и следующей точкой последовательности.

3 Оператор postfix - аналогичен оператору postfix ++, за исключением того, что значение операнда уменьшается (т. Е. Из него вычитается значение 1 соответствующего типа).

6.5.3.1 Префиксные операторы увеличения и уменьшения

Ограничения

1 Операнд префиксного оператора увеличения или уменьшения должен иметь квалифицированный или неквалифицированный вещественный или указательный тип и должен быть изменяемым lvalue.

Семантика

2 Значение операнда оператора префикса ++ увеличивается. Результатом является новое значение операнда после увеличения. Выражение ++E эквивалентно (E+=1). См. Обсуждение аддитивных операторов и составного присваивания для получения информации об ограничениях, типах, побочных эффектах и ​​преобразованиях, а также о влиянии операций на указатели.

3 Префиксный оператор аналогичен префиксному оператору ++, за исключением того, что значение операнда уменьшается.

      #include<stdio.h>
void main(){
char arr[] ="abcd";
char *p=arr,*q=arr;
char k,temp;
temp = *p++; /* here first it assigns value present in address which
is hold by p and then p points to next address.*/
k = ++*q;/*here increments the value present in address which is 
hold by q and assigns to k and also stores the incremented value in the same 
address location. that why *q will get 'h'.*/
printf("k is %c\n",k); //output: k is h
printf("temp is %c\n",temp);//output: temp is g
printf("*p is %c\n",*p);//output: *p is e
printf("*q is %c",*q);//output: *q is h
}

Пост и предварительное приращение с указателями

Предварительное увеличение перед значением приращения ++ например:

(++v) or 1 + v

Пост приращения после увеличения значения ++ например:

(rmv++) or rmv + 1

Программа:

int rmv = 10, vivek = 10;
cout << "rmv++ = " << rmv++ << endl; // the value is 10
cout << "++vivek = " << ++vivek; // the value is 11

Вы также должны знать, что поведение операторов постинкремента / декремента отличается в C/C++ и Java.

Дано

  int a=1;

в C/C++ выражение

 a++ + a++ + a++

оценивает до 3, а в Java - до 6. Угадайте почему...

Этот пример еще более запутанный:

cout << a++ + a++ + a++ << "<->" << a++ + a++ ;

печатает 9<->2!! Это потому, что вышеприведенное выражение эквивалентно:

operator<<( 
  operator<<( 
    operator<<( cout, a++ + a++ ), 
    "<->"
  ), 
  a++ + a++ + a++ 
)
Другие вопросы по тегам