четверг, 13 ноября 2014 г.

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

В Си есть два оператора, предназначенных для увеличения и уменьшения переменных. Оператор инкремента ++ добавляет 1 к своему операнду, а оператор декремента -- вычитает 1.

Необычность операторов ++ и -- в том, что их можно использовать и как префиксные (помещая перед переменной: ++n), и как постфиксные (помещая после переменной: n++) операторы. В обоих случаях значение n увеличивается на 1, но выражение ++n увеличивает n до того, как его значение будет использовано,
а n++ — после того.

Предположим, что n содержит 5, тогда


x = n++;
установит x в значение 5, а
x = ++n;
установит х в значение 6. И в том и другом случае n станет равным 6.

Операторы инкремента и декремента можно применять только к переменным. Выражения вроде (i+j)++ недопустимы.

Если требуется только увеличить или уменьшить значение переменной (но не получить ее значение), как например

if (c == '\n')
    nl++;
то безразлично, какой оператор выбрать — префиксный или постфиксный.

Но существуют ситуации, когда требуется оператор вполне определенного типа. В качестве примера, авторы книги предлагают рассмотреть функцию
squeeze(s, с), которая удаляет из строки s все символы, совпадающие с c:

#include <stdio.h>
#define MAXLINE 1000 /* максимальный размер вводимой строки */

int getstr(char line[], int maxline);
void squeeze(char s[], int с);

int c = 65; /* Символ 'A' */

int main(void)
{
int len = 0;
char line[MAXLINE]; /* текущая строка */

while ((len = getstr(line, MAXLINE)) > 0)
{
squeeze(line, c);
printf("%s", line);
}

return 0;
}

/* getline: читает строку в s, возвращает длину */
int getstr(char s[], int lim)
{
int c, i;

for (i = 0; i < lim - 1 && (c = getchar()) != EOF && c != '\n'; ++i)
s[i] = c;
if (c == '\n')
{
s[i] = c;
++i;
}
s[i] = '\0'; /* в конец строки дописывам "0" */
return i; /* функция возвращает длину строки */
}

/* squeeze: удаляет все с из s */
void squeeze(char s[], int с)
{
int i, j;
for (i = j = 0; s[i] != '\0'; i++)
if (s[i] != c)
s[j++] = s[i];
s[i] = '\0';
}



#include <stdio.h>
#define MAXLINE 1000 /* максимальный размер вводимой строки */

int getstr(char line[], int maxline);
void squeeze(char line[], int symbol);

int main(void)
{
int len = 0;
char line[MAXLINE]; /* текущая строка */

int c = 65; /* Символ 'A' */

while ((len = getstr(line, MAXLINE)) > 0)
{
squeeze(line, c);
printf("%s", line);
}

return 0;
}

/* getline: читает строку в s, возвращает длину */
int getstr(char s[], int lim)
{
int c, i;

for (i = 0; i < lim - 1 && (c = getchar()) != EOF && c != '\n'; ++i)
s[i] = c;
if (c == '\n')
{
s[i] = c;
++i;
}
s[i] = '\0'; /* в конец строки дописывам "0" */
return i; /* функция возвращает длину строки */
}

/* squeeze: удаляет все с из s */
void squeeze(char s[], int symb)
{
int i, j;
for (i = j = 0; s[i] != '\0'; i++)
if (s[i] != symb)
s[j++] = s[i];
s[i] = '\0';

}
Каждый раз, когда встречается символ, отличный от с, он копируется в текущую j-ю позицию, и только после этого переменная j увеличивается на 1, подготавливаясь таким образом к приему следующего символа. Это в точности совпадает со следующими действиями:

if (s[i] != с) {
    s[j] = s[i];
    j++;
}

Другой пример — функция getline. Приведенную там запись


if (с == '\n' ) {
    s[i] = с;
    ++i;
}
можно переписать более компактно:
if (с == '\n' )
    s[i++] = с;



В качестве третьего примера рассматривается функция strcut(s, t), которая строку t помещает в конец строки s. Предполагается, что в s достаточно места, чтобы разместить там суммарную строку. strcut написана так, что она не возвращает никакого результата. На самом деле библиотечная strcat возвращает указатель на результирующую строку.

#include <stdio.h>
#define MAXLINE 1000 /* максимальный размер вводимой строки */

int getstr(char line[], int maxline);
void strcut(char line[], char new_line[]);


int main(void)
{
int len = 0;
char line[MAXLINE]; /* текущая строка */
char new_line[] = "This is the end!";

while ((len = getstr(line, MAXLINE)) > 0)
{
strcut(line, new_line);
printf("%s", line);
}

return 0;
}

/* getline: читает строку в s, возвращает длину */
int getstr(char s[], int lim)
{
int c, i;

for (i = 0; i < lim - 1 && (c = getchar()) != EOF && c != '\n'; ++i)
s[i] = c;
if (c == '\n')
s[i++] = c;
s[i] = '\0'; /* в конец строки дописывам "0" */
return i; /* функция возвращает длину строки */
}

/* strcut: помещает t в конец s; s достаточно велика */
void strcut(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 постфиксный оператор ++ применяется и к i, и к j, чтобы на каждом шаге цикла переменные i и j правильно отслеживали позиции перемещаемого символа.

Комментариев нет:

Отправить комментарий