Постинкрементная и прединкрементная концепция?
Я не понимаю концепцию постфикса и префикса увеличения или уменьшения. Кто-нибудь может дать лучшее объяснение?
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++
)