netlib.narod.ru | < Назад | Оглавление | Далее > |
В Си есть два необычных оператора, предназначенных для увеличения и уменьшения переменных. Оператор инкремента ++ добавляет 1 к своему операнду, а оператор декремента -- вычитает 1. Мы уже неоднократно использовали оператор ++ для увеличения значения переменных, например
if (c == '\n') ++nl;
Необычность операторов ++ и -- в том, что их можно использовать и как префиксные (помещая перед переменной: ++n), и как постфиксные (помещая после переменной: n++). В обоих случаях значение n увеличивается на 1, но выражение ++n увеличивает n до того, как его значение будет использовано, а n++ — после того. Предположим, что переменная n содержит число 5, тогда
x = n++;
присвоит x значение 5, а
x = ++n;
присвоит x значение 6. И в том и в другом случае n станет равным 6. Операторы инкремента и декремента можно применять только к переменным. Выражения вроде (i + j)++ недопустимы.
Если требуется только увеличить или умеьшить значение переменной, а не использовать ее значение, как например, в инструкции
if (c == '\n') nl++;
то безразлично, какой оператор выбрать — префиксный или постфиксный. Но существуют ситуации, когда требуется использовать оператор вполне определенного типа. Например, рассмотрим функцию squeeze(s, c), которая удаляет из строки s все символы, совпадающие с c:
/* squeeze: удаление из строки s символов, совпадающих с с */ void squeeze(char s[], int c) { int i,j; for (i = j = 0; s[i] != '\0'; i++) if (s[i] != c) s[j++] = s[i]; s[j] = '\0'; }
Каждый раз, когда встречается символ, отличный от c, он копируется в текущую j-ю позицию, и только после этого переменная j увеличивается на 1, подготавливаясь таким образом к приему следующего символа. Это в точности совпадает со следующими действиями:
if (s[i] != c) { s[j] = s[i]; j++; }
Другой пример — функция getline, которая нам известна по главе 1. Приведенную там запись
if (c == '\n') { s[i] = c; ++i; }
можно переписать более компактно:
if (c == '\n') s[i++] = c;
В качестве третьего примера рассмотрим стандартную функцию strcat(s, t), которая строку t записывает в конец строки s. Предполагается, что в строке s достаточно места для размещения обоих строк. Мы написали strcat так, что она не возвращает никакого результата. На самом деле библиотечная функция strcat возвращает указатель на результирующую строку.
/* strcat: помещает строку t в конец строки s Строка s должна быть достаточно велика */ void strcat (char s[], shar t[]) { int i, j; i = j = 0; while (s[i] != '\0') /* находим конец строки s */ i++; while ((s[i++] = t[j++]) != '\0' /* копируем t */ ; }
При копировании очередного символа из t в s постфиксный оператор ++ применяется и к i, и к j, чтобы на каждом шаге цикла переменные i и j правильно отслеживали позиции перемещаемого символа.
Упражнение 2-4 |
Напишите версию функции squeeze(s1, s2), которая удаляет из строки s1 все символы, встречающиеся в строке s2. |
Упражнение 2-5 |
Напишите функцию any(s1, s2), которая возвращает либо ту позицию в строке s1, где стоит первый символ, совпавший с любым из символов строки s2, либо -1, если ни один из символов строки s1 не совпадает с символами строки s2. (Стандартная библиотечная функция strpbrk делает то же самое, но выдает не номер позиции символа, а указатель на символ.) |
netlib.narod.ru | < Назад | Оглавление | Далее > |