C забезпечує двома незвичними операторами приросту та спаду змінних. Оператор приросту ++додає 1 до свого операнду, тоді як --, навпаки, віднімає 1. Ми вже не раз користувалися ++ для збільшення значення змінних, як, наприклад, у
if (c == '\n')
++nl;
Незвична сторона полягає в тому, що як ++, так і -- можуть використовуватись як префіксні оператори (перед змінною, наприклад ++n), так і постфіксні (після змінної: n++). В обох випадках, як наслідок — збільшується значення n. Але вираз ++n збільшує n до того, як це значення буде використане, тоді як n++ збільшує n після того, як було використане початкове значення. Це означає, що в контексті, де дійсно використовується значення, а не тільки самий ефект, ++n і n++ — відмінні. Якщо n дорівнює 5, тоді
x = n++;
присвоїть x значення 5, зате у випадку
x = ++n;
x дорівнюватиме вже 6. В обох випадках, n стане рівним 6. Оператори приросту та спаду можуть використовуватись тільки зі змінними; вирази на кшталт (i+j)++ заборонені.
У контексті, коли значення не потрібне, а тільки ефект приросту, як наприклад
if (c == '\n')
nl++;
префікс і постфікс тотожні. Але існують випадки, коли треба звернутися тільки до одного, або тільки до іншого. Наприклад, розглянемо функцію squeeze(s,c), яка вилучає всі знайдені знаки c з ланцюжка s.
/* squeeze: вилучає всі c з 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збільшено, щоб бути готовим до наступного знака. Це точний еквівалент
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. strcat припускає, що s має досить місця, щоб зберегти комбінацію обох ланцюжків. Так, як ми це написали, strcat не повертає жодного значення; версія зі стандартної бібліотеки повертає покажчик на отриманий ланцюжок.
/* strcat: зчеплює t із кінцем s; s має бути досить великим */
void strcat(char s[], char t[])
{
int i, j;
i = j = 0;
while (s[i] != '\0') /* знаходить кінець s */
i++;
while ((s[i++] = t[j++]) != '\0') /* копіює t */
;
}
Одночасно з копіюванням t до s до них застосовано постфіксний ++, щоб упевнитись, що вони в позиції для наступного проходження через цикл.
Вправа 2-4. Напишіть альтернативну версію squeeze(s1,s2), яка би вилучала кожний знак ізs1, який збігається із будь-яким знаком s2.
Вправа 2-5. Напишіть функцію any(s1, s2), яка повертає перше положення в ланцюжку s1одного із знаків ланцюжка s2, або -1, якщо жодного не знайдено. (Функція strpbrk зі стандартної бібліотеки здійснює те саме, тільки повертає покажчик на положення.)