В языке Си существует несколько операторов, которые позволяют реализовать циклические вычисления (итерации). В этом параграфе мы рассмотрим программные конструкции циклов с операторами for, while, dowhile. Оператор FOR.
Оператор FOR. Оператор for предназначен для реализации циклов со счетчиком. В операторе for могут автоматически реализоваться сразу три операции: инициализация счётчика цикла, проверка его значения и модификация. Рассмотрим типичный пример реализации цикла с оператором for:
1 for ( i = 0 ; i
В строке 1 записывается сам оператор for, за которым обязательно следуют три выражения, заключенные в круглые скобки. Выражение 1 вычисляется один и только один раз перед проверкой условия цикла. В нашем примере выражение 1 присваивает начальное значение переменной i. Выражения два и три могут иметь произвольный характер, но обычно их используют для проверки и модификации условия продолжения цикла. Выражение 2 задаёт условие продолжения цикла. Если его значение отлично от нуля («истина»), будут выполнены операторы 3…7, составляющие тело цикла. После этого вычисляется выражение 3, указанное в скобках первой строки. В нашем примере выражение i = i + += i + 1 осуществляет увеличение на 1 внутреннего счетчика циклов оператора for. Поэтому операторы тела цикла 3…7 будут выполняться 10 раз при значениях переменной цикла i от 0 до 9. В конце первого цикла значение i будет равно 1, в конце второго – i=2, и т.д. В конце десятого цикла переменная i примет значение 10. Далее начнется исполнение 11-ого цикла оператора for, но, проанализировав условие выражения 2 оператора for, программа выйдет из цикла, не исполняя операторов тела цикла. Достаточно часто переменная счетчика циклов оператора for используется также в теле цикла этого оператора. Например, следующий программный фрагмент вычисляет таблицу соответствия значений температуры, записанных по шкале Цельсия и по шкале Фарингейта, и последовательно выводит эти значения на экран монитора. Диапазон исходных значений температуры составляет от –10 C до +40 C.
1 for ( k = -10 ; k
Второй способ организации циклов использует оператор while. Применение оператора while иллюстрирует следующий программный фрагмент:
1 k= -10 2 while ( k < 40 ) 3 < 4 Temperature = k*9/5+32; 5 k + + 6 printf(«Current temperature is %fn», Temperature); 7 >
В отличие от оператора for, переменная k, используемая в качестве счетчика циклов, должна быть инициализирована перед оператором while, например, в строке 1. Обратите внимание, что в строке 2 в скобках оператора while записано всего лишь одно выражение, которое называется условием цикла. Выполнение оператора while начинается с вычисления этого выражения. Если значение выражения отлично от нуля («истина»), то выполняются операторы 4..6 тела цикла. После выполнения операторов тела цикла снова вычисляется выражение условия и процесс повторяется. Таким образом, выполнение тела цикла происходит пока значение выражения условия цикла отлично от нуля («истина»). Следует заметить, что если условие цикла не выполнится на первой итерации, то тело цикла не будет выполнено ни разу. Для того чтобы тело цикла выполнялось хотя бы один раз, в языке Си предусмотрен оператор do-while, который рассматривается далее. Одним из результатов выполнения тела цикла, как правило, является изменение условия цикла, иначе цикл будет бесконечным. Но, естественно, возможны случаи, когда условие цикла зависит от результата работы вызываемой из выражения функции, или условие цикла меняется в функции обработки прерывания, которая активизируется во время выполнения тела цикла. Тело цикла может вообще отсутствовать, в случае применения на его месте пустого оператора. Это бывает нужно, например, при программном ожидании установки какоголибо аппаратного флага микроконтроллера, который изменяется встроенной периферией. С помощью оператора while можно создавать бесконечные циклы.
#23. Оператор цикла for | Язык C для начинающих
Третий способ организации циклов в Си использует оператор dowhile. Пример записи вычисления таблицы соответствия температур с использованием оператора do-while приведен ниже:
1 k= -10 2 do 3 < 4 Temperature = k*9/5+32; 5 k + + 6 printf(«Current temperature is %fn», Temperature); 7 >8 while ( k < 40 )
Оператор do продолжает циклическое исполнение операторов тела цикла 4…6 до тех пор, пока значение выражения 1 не станет равным нулю («ложным»). Оператор do-while похож на оператор while, но условие цикла в нём вычисляется и проверяется после очередного исполнения операторов тела цикла. Таким образом, операторы тела цикла выполняются, по крайней мере, один раз, даже если условие цикла заведомо ложно.
Цикл do..while
В цикле do..while сначала выполняется код цикла, а потом происходит проверка условия в инструкции while . И пока это условие истинно, то есть не равно 0, то цикл повторяется.
do < // действия цикла >while (условие);
#include int main(void) < int i = 6; do < printf(«%d», i); i—; >while (i > 0); return 0; >
Здесь код цикла сработает 6 раз, пока i не станет равным нулю. Но важно отметить, что цикл do гарантирует хотя бы единократное выполнение действий, даже если перед первым выполнением условие в инструкции while не будет истинно. То есть мы можем написать:
int i = -1; do < printf(«%d», i); i—; >while (i > 0);
Хотя у нас переменная i меньше 0, цикл все равно один раз выполнится.
Цикл while
В отличие от цикла do цикл while сразу проверяет истинность некоторого условия, и если условие истинно, то есть не равно 0, то код цикла выполняется:
while(условие) < // выполняемые инструкции, если условие истинно >
Например, выведем на консоль все числа от 6 до 1:
#include int main(void) < int i = 6; while (i >0) < printf(«%d n», i); i—; >return 0; >
Здесь, пока истинно условие i > 0 , будут выполняться действия цикла — printf(«%d n», i) и i—
Цикл do-while
Цикл do-while отличается от while лишь тем, что его тело будет выполнено хотя бы один раз независимо от условия выполнения цикла. Синтаксис цикла do-while можно описать так (фигурные скобки необязательны, если выражение только одно):
do < выражение1; …; >while (логич_выражение);
Этот цикл называют циклом с постусловием. Его используют реже обычного while . В принципе почти всегда можно обойтись без do-while , но в определенных ситуациях его использование упрощает код. Допустим требуется вывести на экран отдельные цифры числа. Любое число состоит хотя бы из одной цифры, даже число 0. Можно решить эту задачу с использованием цикла while :
while (a > 0) { printf(«%dn», a % 10); a = a / 10; }
Но в этом случае, если a равно 0, то цикл не выполнится ни разу. Пришлось бы перед циклом использовать инструкцию if , в которой сравнивать переменную с 0. Использование же цикла do-while решает эту проблему, т. к. его тело один раз выполнится даже при нулевом значении переменной:
do { printf(«%dn», a % 10); a = a / 10; } while (a > 0);
Цикл for
Представим синтаксис заголовка цикла for языка программирования C так:
for (часть1; часть2; часть3)
Вот так будет выглядеть программный код, выводящий таблицу символов на экран, в котором используется цикл for :
unsigned char a; for (a = 31; a 128; a++) { if (a % 10 == 0) printf(«n»); printf(«%4d-%c», a, a); } printf(«n»);
Напишите программу с использованием цикла for , выводящую на экран таблицу умножения (Подсказка: как и в случае с while следует использовать два цикла — внешний и вложенный.)
Цикл Do While
Цикл схож с циклом while по форме написания, но при этом работает немного по-другому. Цикл do..while будет выполнен один раз сто процентов, а дальше проверит условие и если оно верно, то цикл будет выполняться дальше:
int x = 13; do < x—; printf(«%dn», i); >while (x > 10);
Как видно из примера, цикл изначально неверный, но это не мешает ему сработать один раз.
Операторы для работы в циклах
Существует два основных оператора для работы в циклах:
- Оператор break — служит для выхода из цикла полностью;
- Оператор continue — пропускает лишь одну итерацию и не выходит из цикла.
Весь код будет доступен после подписки на проект!
Задание к уроку
Необходимо оформить подписку на проект, чтобы получить доступ ко всем домашним заданиям
Большое задание по курсу
Вам необходимо оформить подписку на сайте, чтобы иметь доступ ко всем большим заданиям. В задание входит методика решения, а также готовый проект с ответом к заданию.
PS: подобные задания доступны при подписке от 1 месяца
Цикл с предусловием while
Общая форма записи
while (Условие)
БлокОпераций;
>
Если Условие выполняется (выражение, проверяющее Условие , не равно нулю), то выполняется БлокОпераций , заключенный в фигурные скобки, затем Условие проверяется снова. Последовательность действий, состоящая из проверки Условия и выполнения БлокаОпераций , повторяется до тех пор, пока выражение, проверяющее Условие , не станет ложным (равным нулю). При этом происходит выход из цикла, и производится выполнение операции, стоящей после оператора цикла.
Пример на Си : Посчитать сумму чисел от 1 до введенного k
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#define _CRT_SECURE_NO_WARNINGS // для возможности использования scanf
#include
int main() int k; // объявляем целую переменную key
int i = 1;
int sum = 0; // начальное значение суммы равно 0
printf( «k = » );
scanf( «%d» , // вводим значение переменной k
while (i // пока i меньше или равно k
sum = sum + i; // добавляем значение i к сумме
i++; // увеличиваем i на 1
>
printf( «sum = %dn» , sum); // вывод значения суммы
getchar(); getchar();
return 0;
>
При построении цикла while , в него необходимо включить конструкции, изменяющие величину проверяемого выражения так, чтобы в конце концов оно стало ложным (равным нулю). Иначе выполнение цикла будет осуществляться бесконечно (бесконечный цикл).
Пример бесконечного цикла
while (1)
БлокОпераций;
>
while — цикл с предусловием, поэтому вполне возможно, что тело цикла не будет выполнено ни разу если в момент первой проверки проверяемое условие окажется ложным.
Например, если в приведенном выше коде программы ввести k=-1, то получим результат
Цикл с постусловием do. while
Общая форма записи
do <
БлокОпераций;
> while (Условие);
Цикл do…while — это цикл с постусловием, где истинность выражения, проверяющего Условие проверяется после выполнения Блока Операций , заключенного в фигурные скобки. Тело цикла выполняется до тех пор, пока выражение, проверяющее Условие , не станет ложным, то есть тело цикла с постусловием выполнится хотя бы один раз.
Использовать цикл do…while лучше в тех случаях, когда должна быть выполнена хотя бы одна итерация, либо когда инициализация объектов, участвующих в проверке условия, происходит внутри тела цикла.
Пример на Си . Проверка, что пользователь ввел число от 0 до 10
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#define _CRT_SECURE_NO_WARNINGS // для возможности использования scanf
#include
#include // для использования функции system()
int main()
int num; // объявляем целую переменную для числа
system( «chcp 1251» ); // переходим на русский язык в консоли
system( «cls» ); // очищаем экран
do printf( «Введите число от 0 до 10: » ); // приглашение пользователю
scanf( «%d» , // ввод числа
> while ((num 10)); // повторяем цикл пока num 10
printf( «Вы ввели число %d» , num); // выводим введенное значение num — от 0 до 10
getchar(); getchar();
return 0;
>
Циклы с постусловием.
Ц икл с постусловием отличается от цикла while тем, что условие в нём проверяется после выполнения цикла, то есть этот цикл будет повторён как минимум один раз (в отличие от цикла while, который может вообще не выполняться). Синтаксис цикла
do < тело цикла >while(условие);
Предыдущий пример с использованием цикла do будет выглядеть как
int i = 0; do < printf(«%dn», i); i++; >while(i < 10);
Давайте рассмотрим пример использования цикла с постусловием и предусловием. Пусть нам необходимо проинтегрировать функцию.
∫ a b f x d x
Интеграл — это сумма бесконечно малых. Мы можем представить интеграл как сумму, а бесконечно малые значения просто заменить маленькими значениями.
∫ a b f x d x = ∑ i = a b f i h
Из формулы видно, что мы на самом деле разбили площадь под графиком на множество прямоугольников, где высота прямоугольника — это значение функции в точке, а ширина — это наш шаг. Сложив площади всех прямоугольников, мы тем самым получим значение интеграла с некоторой погрешностью.
Пусть искомой функцией будет x 2 . Нам понадобятся следующие переменные. Во-первых, аккумулятор sum для хранения интеграла. Во-вторых, левая и правая границы a и b, в третьих — шаг h. Также нам понадобится текущее значение аргумента функции x.
Для нахождения интеграла необходимо пройти от a до b с некоторым шагом h, и прибавлять к сумме площадь прямоугольника со сторонами f(x) и h.
#include #include int main() < double sum = 0.0; double a = 0.0; double b = 1.0; double h = 0.01; double x = a; while (x < b) < sum += x*x * h; x += h; >printf(«%.3f», sum); getch(); >
Программа выводит 0.328.
∫ 0 1 x 2 d x = x 3 3 | 0 1 = 1 3 ≈ 0.333
Если посмотреть на график, то видно, что каждый раз мы находим значение функции в левой точке. Поэтому такой метод численного интегрирования называют методом левых прямоугольников. Аналогично, можно взять правое значение. Тогда это будет метод правых прямоугольников.
while (x
Сумма в этом случае будет равна 0.338. Метод левых и правых прямоугольников не очень точен. Мы фактически аппроксимировали (приблизили) гладкий график монотонно возрастающей функции гистограммой. Если немного подумать, то аппроксимацию можно проводить не только суммируя прямоугольники, но и суммируя трапеции.
Приближение с помощью трапеций на самом деле является кусочной аппроксимацией кривыми первого порядка (ax+b). Мы соединяем точки на графике с помощью отрезков. Можно усложнить, соединяя точки не отрезками, а кусками параболы, тогда это будет метод Симпсона. Если ещё усложнить, то придём к сплайн интерполяции, но это уже другой, очень долгий разговор.
Вернёмся к нашим баранам. Рассмотрим 4 цикла.
int i = 0; while ( i++
int i = 0; while ( ++i
int i = 0; do < printf(«%d «, i); >while(i++ < 3);
int i = 0; do < printf(«%d «, i); >while(++i < 3);
Если выполнить эти примеры, то будет видно, что циклы выполняются от двух, до четырёх раз. На это стоит обратить внимание, потому что неверное изменение счётчика цикла часто приводит к ошибкам.
Часто случается, что нам необходимо выйти из цикла, не дожидаясь, пока будет поднят какой-то флаг, или значение переменной изменится. Для этих целей служит оператор break, который заставляет программу выйти из текущего цикла.
Давайте решим простую задачу. Пользователь вводит числа до тех пор, пока не будет введено число 0, после этого выводит самое большое из введённых. Здесь есть одна загвоздка. Сколько чисел введёт пользователь не известно. Поэтому мы создадим бесконечный цикл, а выходить из него будем с помощью оператора break. Внутри цикла мы будем получать от пользователя данные и выбирать максимальное число.
#include #include int main() < int num = 0; int max = num; printf(«To quit, enter 0n»); /*бесконечный цикл*/ while (1) < printf(«Please, enter number: «); scanf(«%d», /*условие выхода из цикла*/ if (num == 0) < break; >if (num > max) < max = num; >> printf(«max number was %d», max); getch(); >
Напомню, что в си нет специального булевого типа. Вместо него используются числа. Ноль — это ложь, все остальные значения – это истина. Цикл while(1) будет выполняться бесконечно. Единственной точкой выхода из него является условие
if (num == 0)
В этом случае мы выходим из цикла с помощью break; Для начала в качестве максимального задаём 0. Пользователь вводит число, после чего мы проверяем, ноль это или нет. Если это не ноль, то сравниваем его с текущим максимальным.
Бесконечные циклы используются достаточно часто, так как не всегда заранее известны входные данные, либо они могут меняться во время работы программы.
Когда нам необходимо пропустить тело цикла, но при этом продолжить выполнение цикла, используется оператор continue. Простой пример: пользователь вводит десять чисел. Найти сумму всех положительных чисел, которые он ввёл.
#include #include int main() < int i = 0; int positiveCnt = 0; float sum = 0.0f; float input; printf(«Enter 10 numbersn»); while (i < 10) < i++; printf(«%2d: «, i); scanf(«%f», if (input sum += input; positiveCnt++; > printf(«Sum of %d positive numbers = %f», positiveCnt, sum); getch(); >
Пример кажется несколько притянутым за уши, хотя в общем он отражает смысл оператора continue. В этом примере переменная positiveCnt является счётчиком положительных чисел, sum сумма, а input — временная переменная для ввода чисел.
Вот ещё один пример. Необходимо, чтобы пользователь ввёл целое число больше нуля и меньше 100. Пока необходимое число не будет введено, программа будет продолжать опрос.
do < printf(«Please, enter number: «); scanf(«%d», if (n < 0 || n>100) < printf(«bad number, try againn»); continue; >else < break; >> while (1);
Цикл for
О дним из самых используемых является цикл со счётчиком for. Его синтаксис
Например, выведем квадраты первых ста чисел.
int i; for (i = 1; i
Одним из замечательных моментов цикла for является то, что он может работать не только с целыми числами.
float num; for (num = 5.3f; num > 0f; num -= 0.2)
Этот цикл выведет числа от 5.3 до 0.1. Цикл for может не иметь некоторых «блоков» кода, например, может отсутствовать инициализация, проверка (тогда цикл становится бесконечным) или изменение счётчика. Вот пример с интегралом, реализованный с применением счётчика for
#include #include int main() < double sum = 0.0; double a = 0.0; double b = 1.0; double h = 0.01; double x; for (x = a; x < b; x += h) < sum += x*x * h; >printf(«%.3f», sum); getch(); >
Давайте рассмотрим кусок кода
double x ; for (x = a; x
Его можно изменить так
double x = a; for (; x
Более того, используя оператор break, можно убрать условие и написать
double x; for (x = a;; x += h)< if (x>b) < break; >sum += x*x*h; >
double x = a; for (;;) < if (x >b) < break; >sum += x*x*h; x += h; >
кроме того, используя оператор «,», можно часть действий перенести
double x ; for (x = a; x < b; x += h, sum += x*x*h) ;
ЗАМЕЧАНИЕ: несмотря на то, что так можно делать, пожалуйста, не делайте так! Это ухудшает читаемость кода и приводит к трудноуловимым ошибкам.
Давайте решим какую-нибудь практическую задачу посложнее. Пусть у нас имеется функция f(x). Найдём максимум её производной на отрезке. Как найти производную функции численно? Очевидно, по определению). Производная функции в точке — это тангенс угла наклона касательной.
f x ′ = d x d y
Возьмём точку на кривой с координатами (x; f(x)), сдвинемся на шаг h вперёд, получим точку (x+h, f(x+h)), тогда производная будет
d x d y = f ( x + h ) — f x ( x + h — x ) = tg α
То есть, отношение малого приращения функции к малому приращению аргумента. Внимательный читатель может задать вопрос, почему мы двигаемся вперёд по функции, а не назад. Ну пойдёмте назад
Возьмём среднее от этих двух значений, получим
В общем-то теперь задача становится тривиальной: идём от точки a до точки b и находим минимальное значение производной, а также точку, в которой производная принимает это значение. Для решения нам понадобятся, как и в задаче с интегралом, переменные для границ области поиска a и b, текущее значение x и шаг h. Кроме того, необходимо максимальное значение maxVal и координата maxX этого максимального значения. Для работы возьмём функцию x • sin x
#include #include #include int main() < double a = 0; double b = 3.0; double h = 0.001; double h2 = h * 2.0; double maxVal = a*sin(a); double maxX = a; double curVal; double x; // Проходим по всей области от a до b // и ищем максимум первой производной // Используем функцию x*sin(x) for (x = a; x < b; x += h) < curVal = ( (x+h)*sin(x+h)-(x-h)*sin(x-h) )/h2; if (curVal >maxVal) < maxVal = curVal; maxX = x; >> printf(«max value = %.3f at %.3f», maxVal, maxX); getch(); >
На выходе программа выдаёт max value = 1.391 at 1.077
Численное решение даёт такие же (с точностью до погрешности) результаты, что и наша программа.
Классификация
Циклы в СИ и C++ бывают нескольких видов. Всего их три:
- с параметром (счетчиком);
- с постусловием;
- с предусловием.
Особое внимание необходимо уделить циклу с параметром – for. Он встречается в большинстве языков разработки и позволяет реализовывать не только простые алгоритмы, но и достаточно сложные инструкции.
Цикл while
Создать цикл и использовать его в программном коде удается несколькими способами. Первый вариант – это «петля» с предусловием. Используется тогда, когда количество раз выполнения цикла известно заранее.
Форма записи в СИ:
Здесь сначала происходит проверка инструкции, написанной в while, а затем – реализация инструкций. Тело цикла, заключенное в фигурные скобки, будет выполняться до тех пор, пока заданное условие на выходе получает логическое значение истины (равняется true).
С постусловием
Создать «петлю» в программном коде на C++ и Си можно, используя постусловие. Он напоминает предыдущий вариант в обоих языках разработки. при его реализации один проход цикла будет выполняться всегда, независимо от имеющегося условия.
Соответствующий фрагмент позволяет сначала выполнить код цикла в СИ, затем – проверить условия, записанные в инструкции while. Пока оно истинно (не равно 0), алгоритм будет повторяться снова и снова.
Вот – наглядный пример кода:
#include stdio.h int main (void) < int i = 6; do < printf(«%d», i); i—; >while (i > 0); return 0; >
Функция (исходный код) будет работать 6 раз – до тех пор, пока значение переменной i не достигнет 0. «Петля» с do всегда гарантирует выполнение прописанных в теле действий один раз. Это относится даже к ситуациям, при которых первый же результат проверки заданного условия не является истиной.
С параметром
Наиболее простой и распространенный метод, помогающий создавать «петли» – это функция со счетчиком. За нее отвечает оператор for в языке C и C++. Соответствующая запись встречается в большинстве языков разработки. Обозначается при помощи for всегда.
При помощи for можно создать цикл тогда, когда известно точное количество итераций. Они будут известны еще до непосредственного запуска программного обеспечения.
Синтаксическая конструкция for в СИ:
В C++ запись for будет следующей:
Цикл for СИ – это функция, которая включает в себя несколько частей:
- Первая — инициализация. Она осуществляется всего один раз, в самом начале for. Представлена установкой начальных условий. Обычно выражена счетчиками – специальными переменными (h int), используемыми для контроля за циклом.
- Вторая – условие. Оно формирует требование, которое при значении истины (true или 1) будет реализовывать то, что написано в for. В виде условия часто используется операция сравнения.
- Третья – приращение. Является необязательным. Используется в for для определения «шага». Указывает, на сколько система делает увеличение или уменьшение заданного значения переменной при следующей итерации.
Если не указывать приращение, оно будет стандартным – +1. Ниже – пример использования for в C:
- Сначала происходит инициализация счетчика i, значение которого равно 0. I 10 тоже допускается, но в «классическом» примере параметр изначально равняется нулю. Так проще разобраться с принципами работы for.
- Счетчик представляем тип int. Можно воспользоваться любым другим числовым.
- Далее пишется условие, при котором выполняется тело цикла. В заданном примере – до i = 6.
- Последний этап – это приращение. В представленном фрагменте оно будет равно +1. Для уменьшения используется запись i—.
Выше – результат реализации цикла с for, фрагмент которого написан ранее. Для C++ можно рассмотреть такой код:
Соответствующий фрагмент используется для счета суммы всех чисел в пределах от 1 до 1 000.
Операторы Break и Continue
Используя циклы, не только с for, но и другие, может потребоваться «экстренный» выход из соответствующего фрагмента кода. Для этого используются специальные функции. Они почти во всех языках разработки называются одинаково.
Оператор break завершает цикл и выходит из него. К следующей итерации он не переходит:
В заданном фрагменте система выйдет из цикла, когда i будет более 5. Еще один вариант – это использование оператора Continue. В отличие от break, он позволяет перейти к следующей итерации. Пример – можно посчитать сумму только нечетных чисел из заданного разработчиком диапазона.
Пример соответствующего кода приведен выше. Он тоже использует for. Здесь сначала система должна узнать, четное ли заданное число или нет. Для этого применяется процедура нахождения остатка от целочисленного деления на 2. Если соответствующий параметр равен нулю, при помощи continue можно перейти к следующей итерации. В противном случае оно относится к нечетным. Его необходимо прибавить к остальным аналогичным числам.
P. S. Интересует разработка? Обратите внимание на курс «Программист C» . Также в Otus доступно множество других современных курсов. Ниже – один из них: