Операторы инкремента и декремента

Задания раздела 4.5
4.17. Объясните различие между префиксным и постфиксным инкрементом.
4.18. Что будет, если цикл while, используемый для отображения элементов вектора, задействует префиксный оператор инкремента?
4.19. С учетом того, что ptr указывает на тип int, vec - вектор vector<int>, а ival имеет тип int, объясните поведение каждого из следующих выражений. Есть ли среди них правильные? Почему? Как их исправить?
(a) ptr!=0 && *ptr++
(b) ival++&&ival
(c) vec[ival++] <= vec[ival]

Вся теория инкремента и декремента отображена в заданиях, посему сразу начинаю отвечать.

4.17. Объясните различие между префиксным и постфиксным инкрементом.
Префиксный инкремент увеличивается на 1 и возвращает измененный объект как результат. Постфиксный же оператор инкремента обязан хранить копию своего первоначального операнда неизменной, а потом изменять значение операнда.
Постфиксный оператор возвращают копию исходного значения как r-значение, префиксный оператор возвращают объект как l-значение.

4.18. Что будет, если цикл while, используемый для отображения элементов вектора, задействует префиксный оператор инкремента?
Сначала отвечу как будто это кусок теории, а потом про указанную программу. Вот, допустим, программа:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v={0,1,2,3,4,5,6,7,8,9};
auto pbeg=v.begin();
while (pbeg!=v.end()&&*pbeg>=0) {
std::cout << *pbeg++ << std::endl;}
return(0);
}
в которой вывод и инкремент объединены в одну упрощенную запись *pbeg++ (выводим значение указателя, перемещаем указатель на следующую позицию), это упрощенная запись такого выражения:
std::cout << *pbeg << std::endl; pbeg++;
Если в расширенном выражении изменить постфиксный инкремент на префиксный - ничего страшного не случится. Если в упрощенном выражении изменить инкремент на префиксный (*++pbeg), случится ошибочное исполнение программы. Сначала программа выполняет сдвиг на 1, а потом выводит значение. Если бы вектор был незаполненным, то было бы обращение к несуществующему значению.
А теперь программа со страницы:
Программа преобразования всех символов строки со строчной формы в прописную до первого пробела с использованием цикла for выглядела так:
for(auto it=s.begin(); it!=s.end() && !isspace(*it); ++it)
*it=toupper(*it);
Если переписать ту же программу с использованием цикла while:
while (beg!=s.end())&& !isspace(*beg))
*beg=toupper(*beg++); // неопределенное присвоение
Ошибка пересмотренной версии в том, что левый и правый операнды оператора присвоения используют значение, на которое указывает beg, и правый его изменяет. Поэтому присвоение неопределенно. Компилятор может обработать это выражение так:
*beg=toupper(*beg); // сначала обрабатывается левая сторона
*(beg+1)=toupper(*beg); // сначала обрабатывается правая сторона
А так же компилятор может выполнить это любым другим способом, каким захочет.
И куда только делось правостороннее выполнение.
По существу вопроса. Вот программа:
#include <iostream>
#include <vector>
int main()
{
std::vector<char> s={'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'};
auto beg=s.begin();
while (beg!=s.end() && !isspace(*beg)) {
*beg=toupper(*beg++);
}
for (auto i : s) std::cout << i << " ";
return(0);
}
Есть вектор символов, в котором нужно все символы до пробела превратить в прописные.
Вопрос звучал, что будет, если изменить в программе инкремент с постфиксного на префиксный.
*beg=toupper(*++beg);
Вот что будет:

А так если отвечать на вопрос - неверное исполнение программы.

4.19. С учетом того, что ptr указывает на тип int, vec - вектор vector<int>, а ival имеет тип int, объясните поведение каждого из следующих выражений. Есть ли среди них правильные? Почему? Как их исправить?
(a) ptr!=0 && *ptr++
(b) ival++&&ival
(c) vec[ival++] <= vec[ival]

int ival;
int *ptr;
vector<int> vec;
(a) ptr!=0 && *ptr++; /* программа будет работать со значениями, которые являются неопределенными. сравнение указателя ptr * с нулем обычное дело, а вот *ptr++  указывает на значение, которое имеет неопределенное значение */
Вот программа для проверки. Проверьте сами.
#include <iostream>
int main()
{
int ival=1024;
int* ptr=&ival;
if (ptr!=0 && *ptr++) std::cout << *ptr;
return(0);
}
(b) ival++ && ival; /* итерация переменной типа int - увеличение значения на 1, программа странная, но условие вполне допустимо */
(c) vec[ival++] <= vec[ival]; /* при соблюдении некоторых условий это выражение вполне нормальное, что показано в программе ниже */
#include <iostream>
#include <vector>
int main()
{
int ival=0;
int *ptr;
std::vector<int> vec={0,1,2,3};
if (vec[ival]<=vec[ival++]) std::cout << vec[ival++];
return(0);
}

Добавить комментарий