Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Материалы для подготовки к экзамену по ОП.docx
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
297.52 Кб
Скачать

Порядок выполнения логических операторов

&&

Рассмотрим выражение

a && b && c && d

где a, b, c, d – логические значения. Всё выражение равно истине тогда и только тогда, когда все операнды истинны. Если хотя бы один из операндов ложь, то остальные уже не важны. Поэтому, для оптимизации работы, вычисление происходит слева направо и останавливается, как только был найден первый операнд, равный нулю.

В си оператор присваивания может возвращать значение. Иногда он используется непосредственно в условии:

#include <conio.h>

#include <stdio.h>

#include <stdlib.h>

void main() {

int a = 0;

int *p = &a;

if (a && (p = (int*) malloc(sizeof(int) * 2))) {

printf("memory was allocated");

}

free(p);

_getch();

}

В данном случае, оператор malloc не будет выполнен, так как первый операнд a равен 0 (соответственно, всё выражение равно нулю). Таким образом, оператор free попытается очистить память, которую не может очистить (т.к. p продолжит ссылаться на a). Если же мы поменяем a = 1, то всё отработает без проблем.

||

То же самое происходит и при выполнение ||. Выражение

a || b || c || d

выполняется слева направо до тех пор, пока не встретит первое ненулевое значение. После этого выполнение останавливается, так как известно, что всё выражение равно истине.

Очевидно, что это касается не только оператора присваивания, но и любого другого вызова функции. Например, в этом случае функции foo будет вызвана, bar нет.

#include <conio.h>

#include <stdio.h>

#include <stdlib.h>

int foo() {

printf("foo\n");

return 0;

}

int bar() {

printf("bar\n");

return 0;

}

void main() {

int a = 0, b = 1;

if (a || foo() || b || bar()) {

printf("OK\n");

}

_getch();

}

Вывод – не используйте присваивания и вызовов функций (особенно, если они изменяют состояние программы) внутри условий.

Тема №5 Циклы

При решении практических задач постоянно возникает необходимость в повторении действия заданное количество раз, или до достижения какого-либо условия. Например, вывести список всех пользователей, замостить плоскость текстурой, провести вычисления над каждым элементом массива данных и т.п. В си для этих целей используются три вида циклов:

  • с предусловием,

  • постусловием и

  • цикл for со счётчиком (хотя, это условное название, потому что счётчика может и не быть).

Любой цикл состоит из тела и проверки условия, при котором этот цикл должен быть прекращён. Тело цикла - это тот набор инструкций, который необходимо повторять. Каждое повторение цикла называют итерацией.

Цикл с предусловием

int i = 0;

while (i < 10) {

printf("%d\n", i);

i++;

}

Этот цикл выполняется до тех пор, пока истинно условие, заданное после ключевого слова while. Тело цикла - это две строки, одна выводит число, вторая изменяет его. Очевидно, что этот цикл будет выполнен 10 раз и выведет на экран

0

1

2

3

и так далее до 9.

Очень важно, чтобы условие выхода из цикла когда-нибудь выполнилось, иначе произойдёт зацикливание, и программа не завершится. К примеру.

int i = 0;

while (i < 10) {

printf("%d\n", i);

}

В этом цикле не изменяется переменная i, которая служит для определения условия останова, поэтому цикл не завершится.

int i = 0;

while (i > 0) {

printf("%d\n", i);

i++;

}

В этой программе цикл, конечно, завершится, но из-за неправильного действия он будет выполнен гораздо больше 10 раз. Так как си не следит за переполнением переменной, нужно будет ждать, пока переменная переполнится и станет меньше нуля.

int i;

while (i < 10) {

printf("%d\n", i);

i++;

}

У этого примера неопределённое поведение. Так как переменная i заранее не инициализирована, то она хранит мусор, заранее неизвестное значение (зависит от компилятора). При различном содержимом переменной i будет меняться поведение программы.

Если тело цикла while содержит один оператор, то фигурные скобки можно опустить.

int i = 0;

while (i < 10)

printf("%d\n", i++);

Здесь мы инкрементируем переменную i при вызове функции printf. Следует избегать такого стиля кодирования. Отсутствие фигурных скобок, особенно в начале обучения, может приводить к ошибкам. Кроме того, код читается хуже, да и лишние скобки не сильно раздувают листинги.