Операторы, условия и циклы

⏱ 25 мин · 🧩 заданий: 6

Арифметика и присваивание

int x = 10;
x = x + 5;      /* 15 */
x += 5;         /* 20 — краткая запись */
x -= 3; x *= 2; x /= 4; x %= 3;

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

int i = 5;
int a = i++;    /* постфиксный: a = 5, затем i = 6 */
int b = ++i;    /* префиксный: i = 7, затем b = 7 */

Где это встретится

В задаче 8 экзамена есть строка mem->counter++; — увеличение счётчика в разделяемой памяти. Хотя это одна строка C, процессор выполняет её за три шага: прочитать, прибавить, записать. Если два процесса делают это одновременно, одно увеличение может потеряться. Это называется гонка — разберём в модуле о синхронизации.

Сравнения и логика

Оператор Смысл
==, != равно, не равно
<, <=, >, >= сравнения
&& логическое И
\|\| логическое ИЛИ
! логическое НЕ

В C нет отдельного логического типа (в старом стандарте): 0 — ложь, всё остальное — истина. Поэтому пишут if (ptr) вместо if (ptr != NULL).

&& и || вычисляются лениво: если результат ясен по левой части, правая не вычисляется.

if (p != NULL && p->state == 0) { ... }   /* безопасно: при p == NULL правая часть не выполнится */

Побитовые операторы

Оператор Действие Пример (в двоичном)
& И 1100 & 1010 = 1000
\| ИЛИ 1100 \| 1010 = 1110
^ исключающее ИЛИ 1100 ^ 1010 = 0110
~ инверсия ~0000 = 1111
<<, >> сдвиги 1 << 3 = 1000

Системное программирование ими пропитано:

/* комбинирование флагов */
mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);

/* проверка флага */
if (flags & MAP_SHARED) { ... }

/* сброс флага */
flags &= ~MAP_SHARED;

/* разбор виртуального адреса: номер страницы и смещение при странице 4096 байт */
unsigned long page   = addr >> 12;        /* делим на 2^12 */
unsigned long offset = addr & 0xFFF;      /* младшие 12 бит */
Почему сдвиг вместо деления?

Размер страницы — степень двойки. Деление на 2ᵏ — это сдвиг вправо на k бит, а остаток от деления на 2ᵏ — младшие k бит (& (2ᵏ − 1)). Аппаратура MMU именно так и «режет» адрес на номер страницы и смещение: просто берёт нужные провода-биты.

Условия

if (pid == -1) {
    perror("fork");
    _exit(1);
} else if (pid == 0) {
    /* код потомка */
} else {
    /* код родителя: pid > 0 */
}

switch удобен для выбора по целому значению:

switch (sig) {
case SIGINT:
    printf("Ctrl+C\n");
    break;              /* без break выполнение «провалится» в следующий case */
case SIGTERM:
case SIGQUIT:
    printf("завершение\n");
    break;
default:
    printf("другой сигнал\n");
}

Тернарный оператор: int max = (a > b) ? a : b;

Циклы

for (int i = 0; i < 70; i++) {     /* инициализация; условие; шаг */
    sum += a[i] * b[i];
}

while (n > 0) {                    /* проверка до тела */
    n--;
}

do {                               /* тело хотя бы один раз */
    c = getchar();
} while (c != '\n');

for (;;) { ... }                   /* бесконечный цикл; выход — break или return */
  • break — выйти из ближайшего цикла (или switch);
  • continue — перейти к следующей итерации.

Как читать цикл в задаче

Выпишите на бумаге значения переменной цикла и что происходит на каждой итерации. Для циклов с fork рисуйте дерево процессов — у каждого процесса своя копия переменной i.

Итог

  • i++ возвращает старое значение, ++i — новое; counter++ — это три машинных шага.
  • 0 — ложь, не 0 — истина; && и || ленивые.
  • Флаги комбинируют |, проверяют &, сбрасывают &= ~.
  • = — присваивание, == — сравнение.

Практика решено 0 из 6

Вы не вошли — ответы проверяются, но прогресс не сохранится. Войти или зарегистрироваться.
Задание 1 Ввод ответа

Что напечатает программа?

int i = 5;
int a = i++;
int b = ++i;
printf("%d %d %d\n", a, b, i);
Задание 2 Ввод ответа

Сколько раз выполнится тело цикла for (int i = 0; i < 70; i++) { ... }?

Задание 3 Ввод ответа

Чему равно выражение PROT_READ | PROT_WRITE, если PROT_READ = 1, а PROT_WRITE = 2?

Задание 4 Написать код

Проверьте, установлен ли во флагах flags бит MAP_SHARED, и если да — напечатайте shared. Используйте побитовое И: if (flags & MAP_SHARED).

Задание 5 Один вариант ответа

Что произойдёт в этом фрагменте: if (x = 0) printf("zero");?

Задание 6 Ввод ответа

Сколько строк напечатает цикл?

for (int i = 0; i < 10; i++) {
    if (i % 2 == 0) continue;
    if (i > 6) break;
    printf("%d\n", i);
}

Войдите, чтобы отмечать пройденные уроки.