netlib.narod.ru< Назад | Оглавление | Далее >

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

В Си есть два необычных оператора, предназначенных для увеличения и уменьшения переменных. Оператор инкремента ++ добавляет 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< Назад | Оглавление | Далее >

Сайт управляется системой uCoz