Урок 6: «Циклы – это повторяющийся участок кода»

Это последний простой урок, который вы изучите в рамках данной рубрики. Дальше пойдут уже более сложные моменты.

Скажите, не хотелось бы вам хоть что-то указать компилятору, чтобы он автоматически делал сам? Вспомните наш список сотрудников. Мы вручную вводили каждый раз операторы:

cout<<”Введите ФИО сотрудника"<<endl;
cin>>a[1];

Двадцать сотрудников и двадцать таких строчек. Опять же, сотрудников может быть и десять тысяч, тогда можно просто сойти с ума, набивая эта строчки. К счастью, С++ позволяет нам автоматизировать подобные действия. Для этого нужно использовать циклы.

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

Блок-схема – эта графическое отображение алгоритма вашей программы. Имела место в процедурном программировании, с приходом ООП практически потеряла актуальность. Тем не менее, некоторые аспекты удобно отображать именно с помощью блок-схемы.

Эти мои каракули (чертежник из меня никудышный) обозначают цикл с предусловием. Поясню, как работает этот цикл.

Программа доходит до ключевого слова while, обозначающего цикл и проверяет условие, указываемое в скобках. Если оно несовпадает с нужным нам, программа проигнорирует цикл. В другом случае она будет выполнять цикл до достижения нужного условия выхода из цикла. Запомните, цикл с предусловием может не выполниться ни разу! Это его главная особенность.

Объявляется цикл с предусловием так:

while (условие)

{

действия;

}

Давайте теперь рассмотрим на примере, как он действует. Пусть нам нужно будет вывести список чисел, допустим до 20. Итак, наш цикл будет выглядеть таким образом:

intn=0;

while(n>=20)

{

cout<<n<<endl;

n++;

}

Итак, что мы сделали. Вначале инициализировали переменную n нулем. Я мог дать ей единицу, суть не в этом (кстати, попробуйте присвоить n любое другое значение, в том числе и больше 20). Теперь для вывода списка я использовал цикл с предусловием, в котором указал, что цикл

будет выполняться до тех пор, пока n меньше или равен 20. Если переменная достигает 21, то цикл заканчивает свою работу. Ну а в цикле я выводил на консоль значение n, а потом прибавлял ее значение инкрементом (++).

Данный цикл применяется только тогда, когла мы точно не знаем, будет ли выполняться цикл вообще. Я мог присвоить n значение 100 и цикл бы не сработал. Это очень удобно. Компилятор встретил цикл, проверил условие и понял, что ему дальше нужно делать.

В противовес этому цикл, существует цикл с постусловием. Его отличительной чертой является тот факт, что данный цикл выполнится хотя бы один раз, пускай даже, если условие и не будет соответствовать нужному. В итоге это замедляет работу программы. Объявляется цикл с постусловием так:

do

{

действия;

}

while(условие)

Ну а графически это будет выглядеть так:

Как видите, сначала действия выполнются, а уже потом проверяется условие. Чтобы не запутаться, скажу вам сразу – цикл с постусловием следует использовать только тогда, когда необходимо, чтобы цикл сработал хотя бы один раз. В остальных случаях следует использовать цикл с предусловием или цикл с параметром. Давайте нашу задачу реализуем с помощью цикла с постусловием:

int n=0;

do

{

cout<<n<<endl;
 n++; } 
while(n>=20)

Если вы читали урок внимательно, то должны понять разницу между этими двумя циклами. Ради эксперимента вновь поменяйте значение n на больше 20.

Условием цикла может быть и логическое значение:

bool flag=true;

while(flag){

действия;

}

или же

while(!flag)

{

действия;

}

Обратите внимание, что в этом случае будет выполняться бесконечный цикл (цикл, который не может найти условие для выхода). В этом случае его нужно будет явно прервать, например присвоив в первом случае переменной flag значение false:

bool flag=true;

int n=1,k=5;

while (flag)

{

if(++n>--) flag=false;

}

Теперь что за восклицательный знак я поставил перед flag? Это отрицание. Если логическое true, то в следствие знака ! оно будет false. Думаю, что с этим понятно. Просто запомните, что если вдруг вам захотелось проверить условие способом if (flag!=true), то лучше использовать if (!flag).

Думаю, что с этими двумя циклами у вас проблем возникнуть не должно. На практике я знаю, что новички сыплются на следующем виде циклов – цикле с параметром.

 

Что же это за цикл? В предыдущих циклах мы не знали, сколько раз выполнится цикл. Мы ставили условие циклу и компилятор гонял этот цикл. Цикл мог выполниться миллион раз, а мог и не разу.

В отличие от низ, цикл с параметром четко знает, сколько раз он должен выполниться. Ведь мы сами указываем в параметре это значение. Объявляется данный цикл таким образом:

for (нижняя граница цикла; верхняя граница цикла; шаг приращения/ уменьшения)

{

действия

}

На нашем, компьютерном языке C++ он будет записан следующим образом. Кстати, запомните важную вещь – благодаря различным уровням видимости переменных в С (мы об этом поговорим позже), рекомендуется нижнюю границу цикла объявлять в параметре. Кроме того, считается признаком хорошего программирования называть переменную цикла именем I (от iterator). В качестве примера возьмем уже наш многострадальный список сотрудников, который мы рассматривали в прошлом уроке. К слову могу сказать, что для массив и цикл с параметром – это хороший союз. Фактически, этот цикл применяется, в основном, для обхода массива. Хотя им можно решать и другие задачи. Но просто в массиве он очень удобен:

#pragma warning (disable:4786)//отключим предупреждение

#include "stdafx.h"

#include <iostream>; //содержит объекты ввода-вывода

#include <locale.h>; //настройки языка и времени

#include <string>;

using namespace std;

int_tmain(int argc,_TCHAR*argv[])

{

setlocale(0,"");//установим язык по-умолчанию (русский)

constintsize=20;//размер массива

stringsotr[size];

for(int i=0;i<size;i++)

{

cout<<"Введите имя сотрудника"<<endl;

getline(cin,sotr[i]);

}

system("pause");//чтобы окно не закрылось

return0;

}

Скомпилируйте и запустите. У вас должно получиться нечто вроде:

Теперь давайте пробежимся по коду. Вначале директивой #pragma warning (disable:4786) я отключил предупреждения компилятора. В принципе, вы его можете оставить, вот только при компиляции будут доставать «возможные ошибки» (так уж устроен этот компилятор). Важно очень подключить заголовочный файл <string>, в котором находится нужная нам функция getline. Внимание, ввести строку типа string в C++ можно только этой функцией. Объект cin, которым мы раньше пользовались, здесь бесполезен.

Обратите внимание на конструкцию for. Это и есть наш цикл с параметром. Мы объявили итератор, указали, что нижняя граница цикла равна 0 ( а можем любое число использовать, в зависимости от задачи), верхней границе указали, что она меньше константы size (т.к. отчет с 0 для массива, вы же помните?), ну и шаг массива указали равным 1 (использовали для этого инкремент). О функции getline я уже рассказывал.

Попробуйте, модифицируйте программу таким способом, чтобы она выводила список записанных сотрудников из уже введенного массива. Для этого используйте еще один цикл for. Только уже будете выводить таким образом:

cout<<sort[i]<<endl;

Думаю, что вы обратили внимание на то обстоятельство, что вместо индекса массива я использовал значение итератора i. Это тоже самое, как если бы я писан не текущее i, а явно указывал sort [1] и т.д. В этом одно из достоинств массива. К слову, и в двух других циклах вы вольны ввести итератор и сами его приращивать в цикле, давая его значение своему массиву, это хотя и не рекомендуется, но не возбраняется.

Блок-схему рисовать, я считаю, бессмысленно, так как код нагляден. Вместо этого давайте еще немного расскажу о цикле for.

C допускает делать с ним различные безобразия. Вот, например, один из способов вывода ряда фибоначчи:


for (i=0, j=1, k=0, fib =0; i<50; i++, fib=j+k, j=k, k=fib)

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

Кроме этого стоит поговорить о шаге приращения. Его можно задать произвольно. Допустим, нам нужен каждый второй элемент нашего массива. Тогда мы укажем не i++, а i+=2. И так по аналогии. Кроме того, часто нужен будет делать цикл на уменьшение. Тогда нижней границей будет ваше верхнее число, верхней – нижнее, а использовать нужно будет декремент (i—). В алгоритмических приемах вы сами вскоре все увидите.

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


while(true)

{

for(int i=0;i<100;i++)

{

;}

}

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

А вот с break ситуация несколько иная – встретив это слово, C++ прервет работу цикла и выйдет из него. Ему будет абсолютно все равно, что после этого слова стоит еще целый блок действий. Мы указали C++, что хотим прервать цикл по нашему условию.

Давайте продемонстрируем работу break в примере, когда нам нужно будет осуществить линейный (последовательный) поиск в массиве. Хотя и обещал рассмотреть алгоритмы в специальном уроке, но программирование на то и программирование. Без алгоритмов никуда. Линейный поиск – это последовательный перебор элементов с сравнением каждого из них с поисковым запросом. Считается одним из самых медленных алгоритмов. Однако при работе с неупорядоченным массивом (не отсортированным), линейный поиск дает максимальный результат. А так как у нас этот массив некому сортировать, то последовательный поиск – то, что доктор прописал:


for(int i=0;i<size;i++)

{

if(sotr[i]="Иванов")

{

cout<<"Искомая личность найдена"<<endl;

break;

}

}

}

Мы нашли в массиве нашу фамилию (точнее, ее первое вхождение). Дальнейшее выполнение перебора в нашем варианте бессмысленно (мы не учитываем, что могут быть однофамильцы). Поэтому сразу же прерываем цикл. Если условие ни разу не выполнилось, цикл проработает до конца. Думаю, что с этим понятно.

Поэкспериментируйте с оператором continue. Придумайте задачку и реализуйте ее сами. На этом урок о циклах я заканчиваю.

<<Предыдущий урок                                                 Следующий урок>>

Яндекс.Метрика