Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
КРАТКИЙ ОБЗОР С.doc
Скачиваний:
1
Добавлен:
26.10.2018
Размер:
2.11 Mб
Скачать

3.2.3 Инкремент и декремент

Операция ++ явно задает инкремент в отличие от неявного его задания с помощью сложения и присваивания. По определению ++lvalue означает lvalue+=1, что, в свою очередь означает lvalue=lvalue+1 при условии, что содержимое lvalue не вызывает побочных эффектов. Выражение, обозначающее операнд инкремента, вычисляется только один раз. Аналогично обозначается операция декремента (--). Операции ++ и -- могут использоваться как префиксные и постфиксные операции. Значением ++x является новое (т. е. увеличенное на 1) значение x. Например, y=++x эквивалентно y=(x+=1). Напротив, значение x++ равно прежнему значению x. Например, y=x++ эквивалентно y=(t=x,x+=1,t), где t - переменная того же типа, что и x.       Напомним, что операции инкремента и декремента указателя эквивалентны сложению 1 с указателем или вычитанию 1 из указателя, причем вычисление происходит в элементах массива, на который настроен указатель. Так, результатом p++ будет указатель на следующий элемент. Для указателя p типа T* следующее соотношение верно по определению:       long(p+1) == long(p) + sizeof(T);       Чаще всего операции инкремента и декремента используются для изменения переменных в цикле. Например, копирование строки, оканчивающейся нулевым символом, задается следующим образом:       inline void cpy(char* p, const char* q)       {       while (*p++ = *q++) ;       } Язык С++ (подобно С) имеет как сторонников, так и противников именно из-за такого сжатого, использующего сложные выражения стиля программирования. Оператор       while (*p++ = *q++) ; вероятнее всего, покажется невразумительным для незнакомых с С. Имеет смысл повнимательнее посмотреть на такие конструкции, поскольку для C и C++ они не является редкостью.       Сначала рассмотрим более традиционный способ копирования массива символов:       int length = strlen(q)       for (int i = 0; i<=length; i++) p[i] = q[i]; Это неэффективное решение: строка оканчивается нулем; единственный способ найти ее длину - это прочитать ее всю до нулевого символа; в результате строка читается и для установления ее длины, и для копирования, то есть дважды. Поэтому попробуем такой вариант:       for (int i = 0; q[i] !=0 ; i++) p[i] = q[i];       p[i] = 0; // запись нулевого символа Поскольку p и q - указатели, можно обойтись без переменной i, используемой для индексации:       while (*q !=0) {       *p = *q;       p++; // указатель на следующий символ       q++; // указатель на следующий символ       }       *p = 0; // запись нулевого символа Поскольку операция постфиксного инкремента позволяет сначала использовать значение, а затем уже увеличить его, можно переписать цикл так:       while (*q != 0) {       *p++ = *q++;       }       *p = 0; // запись нулевого символа Отметим, что результат выражения *p++ = *q++ равен *q. Следовательно, можно переписать наш пример и так:       while ((*p++ = *q++) != 0) { } В этом варианте учитывается, что *q равно нулю только тогда, когда *q уже скопировано в *p, поэтому можно исключить завершающее присваивание нулевого символа. Наконец, можно еще более сократить запись этого примера, если учесть, что пустой блок не нужен, а операция "!= 0" избыточна, т.к. результат условного выражения и так всегда сравнивается с нулем. В результате мы приходим к первоначальному варианту, который вызывал недоумение:       while (*p++ = *q++) ; Неужели этот вариант труднее понять, чем приведенные выше? Только неопытным программистам на С++ или С! Будет ли последний вариант наиболее эффективным по затратам времени и памяти? Если не считать первого варианта с функцией strlen(), то это неочевидно. Какой из вариантов окажется эффективнее, определяется как спецификой системы команд, так и возможностями транслятора. Наиболее эффективный алгоритм копирования для вашей машины можно найти в стандартной функции копирования строк из файла <string.h>:       int strcpy(char*, const char*);