Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лаб№3.doc
Скачиваний:
0
Добавлен:
01.04.2025
Размер:
162.82 Кб
Скачать

Лабораторная работа №3

Тема:Операторы цикла (for, while, do- while). Операторы break и continue.

Цель: усвоить синтаксис операторов повторения, формировать навыки их использование при организации циклов в программах.

Теоретические сведения Цикл while

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

Обобщенная форма цикла while:

while (выражение) оператор;

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

Пример.

/* Пример выводит на экрон 5 строк типа "Строка" + "индекс" +

"выводится в цикле", где "индекс" меняется от 0 до 4 */

#include < iostream.h >

void main()

{

int i=0; /*Объявление и инициализация переменной i*/

cout << "\n Начало цикла";

while (i!= 5) /*Проверяется выражение (i!=5),

если результат - истина, выполняется операторы тела цикла,

в противном случае управление передается оператору, следующему за циклом. */

{

cout << "Строка " << i << "выводится в цикле \n";

i++;

}

cout << "\n Оператор, следующий за циклом";

}

Пример.

/*Программа выводит на экран данные таблицы умножения на 2*/

#include < iostream.h >

Void main()

{

int i=0;

cout << "Таблица умножения на 2 \n";

while ( i++<10)

cout << i << " *2=" << i*2 << '\n';

cout << "\n Все";

}

Давайте остановимся на операторе while в данном примере и по шагам посмотрим, как он работает.

while (i++<10)

cout << i << " *2="<< i*2 << '\n';

Цикл состоит из двух частей: условие цикла и тело цикла. Обратите внимание на условие цикла - это выражение i++<10 . Условие гласит, что тело цикла будет выполняться, пока выполняется условие i < 10 . После проверки этого условия значение переменной i увеличивается на 1 (об этом говорит оператор i++). Тело цикла состоит всего из одного оператора, а именно:

cout << i << " * 2 = " << i * 2 << '\n';

В данном примере, мы рассмотрели случай с заранее определенным числом повторений, однако характеру оператора while наиболее соотвествуют ситуации, когда заранее неизвестно, количество повторений цикла.

Цикл for

Цикл for используется для организации циклов - повторения каких-либо однородных действий, чаще всего,если число повторений заранее известно.

Вот общий вид цикла for:

for (начальная_инструкция; условие; выражение)

{

инструкции;

}

Семантика (смысл) цикла for такова, что сначала выполняется начальная инструкция; она инициализует переменную, используемую в цикле. Затем проверяется условие. Если оно истинно, то выполняются инструкции, вычисляется выражение, и управление передается обратно в начало цикла for с той разницей, что начальная инструкция уже не выполняется. Это продолжается до тех пор, пока условие не станет ложно, после чего управление передается следующей инструкции. Каждый проход цикла называется итерацией цикла.

Начальной_инструкцией может быть инструкция-выражение или просто объявление.

Цикл for является итерационной инструкцией, используемой обычно с увеличивающейся или уменьшающейся переменной. Например, в следующем коде инструкция for используется для сложения целых чисел от 1 до 10.

sum = 0;

for (i = 1; i <= 10; ++i)

sum += i;

Когда инструкция for начинает выполняться, управляющей переменной i задается начальное значение 1. Затем проверяется условие продолжения цикла i <= 10. Поскольку начальное значение i равно 1, это условие удовлетворяется, так что оператор тела инструкции суммирует к значению переменной sum, равному 0, значение счетчика i, равное 1. Затем управляющая переменная i увеличивается на единицу в выражении ++i и цикл опять начинается с проверки условия его продолжения. Поскольку значение i теперь 2, предельная величина не превышена, так что программа снова выполняет тело цикла. Этот процесс продолжается, пока управляющая переменная i не увеличится до 11 — это приведет к тому, что условие продолжения цикла нарушится и повторение прекратится. Выполнение программы продолжится с первого оператора, расположенного после цикла for.

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

for (sum = 0,i = 1; i <= 10; ++i)

sum += i;

Основное назначение использования оператора запятая — помочь программисту использовать несколько выражений задания начальных значений и (или) несколько выражений приращения переменных. Например, в одной структуре for может быть несколько управляющих переменных, которым надо задавать начальное значение и которые надо изменять. Например:

for(i=0,j=0;i<3,j<`4;i++,j+=2)

cout<<i*j;

Данный цикл проведет две итерации, после которых значение счетчика i станет равным 2, а значение счетчика j = 4. При этом условие для второго счетчик не выполняется (т.к. j строго должен быть меньше 4) и цикл будет прерван. На экране будет выведено 02.

В цикле for может присутствовать локальное объявление переменной управления циклом, как в следующем примере.

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

sum += i*i;

Целая переменная i теперь является объявленной в программе. Это может вносить путаницу, поэтому лучше объявлять все программные переменные в начале блока.

Рассмотрим пример оператора цикла for:

for ( ; ; ) ;

Его заголовок состоит из пустого оператора (ему соответствует первая точка с запятой) и разделителя, который разделяет два пустых выражения. Тело цикла - пустой оператор.

Пустое выражение, определяющее условие выполнения цикла for интерпретируется как всегда истинное условие. Отсутствие условия выполнения предполагает безусловное выполнение.

Рассмотрим принципы работы этого оператора. Цикл состоит из четырёх этапов.

  • Прежде всего, выполняется оператор инициализации цикла. Если он не пустой, выражение за выражением, слева направо. Этот этап можно назвать этапом инициализации цикла. Он выполняется один раз, в самом начале работы цикла.

  • Затем вычисляется значение выражения, которое располагается слева от оператора инициализации. Это выражение называется выражением условия продолжения цикла. Сам этап можно назвать этапом определения условий выполнимости.

  • Если значение этого выражения отлично от нуля (т.е. истинно), выполняется оператор цикла. Этот этап можно назвать этапом выполнения тела цикла.

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

  • На последних двух этапах могут измениться значения ранее определённых переменных. А потому следующий цикл повторяется с этапа определения условий выполнимости.

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

int qwe;

for (qwe < 10; ; ) {}

// Оператор инициализатор построен на основе выражения сравнения.

for (this; ; ) {}

// Оператор инициализатор образован первичным выражением this.

for (qwe; ; ) {}

// Оператор инициализатор образован первичным выражением qwe.

Ещё пример:

int i = 0;

int j;

int val1 = 0;

int val2;

:::::

i = 25;

j = i*2;

:::::

for ( ; i < 100; i++, j--)

{

val1 = i;

val2 - j;

}

Мы имеем оператор цикла for, оператор инициализации которого пуст, а условие выполнения цикла основывается на значении переменной, которая была ранее объявлена и проинициализирована. Заголовок цикла является центром управления цикла. Управление циклом основывается на внешней по отношению к телу цикла информации.

Ещё пример:

for ( int i = 25, int j = i*2; i < 100; i++, j--)

{

val1 = i;

val2 - j;

}

Заголовок нового оператора содержит пару выражений, связанных операцией запятая. Тело оператора представляет всё тот же блок операторов. Что может содержать тело оператора? Любые операторы. Всё, что может называться операторами. От самого простого пустого оператора, до блоков операторов произвольной сложности! Этот блок живёт по своим законам. В нём можно объявлять переменные и константы, а поскольку в нём определена собственная область действия имён, то объявленные в блоке переменные и константы могут скрывать одноимённые объекты с более широкой областью действия имён.

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

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

Рассмотрим несколько примеров. Так, в ходе выполнения оператора цикла

int i;

for (i = 0; i < 10; i++)

{

int j = 0; j += i;

}

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

Объявление переменной i можно расположить непосредственно в теле оператора-инициализатора цикла:

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

{

int j = 0; j += i;

}

И здесь возникает одна проблема. Дело в том, что тело оператора цикла for (оператор или блок операторов) имеет ограниченную область действия имён. А область действия имени, объявленного в операторе-инициализаторе, оказывается шире этой области.

Заголовок цикла for в C++ - центр управления циклом. Здесь следят за внешним миром, за тем, что происходит вне цикла. И потому все обращения к переменным и даже их новые объявления в заголовке цикла относятся к "внешней" области видимости. Следствием такого допущения (его преимущества далеко не очевидны) является правило соотнесения имени, объявленного в заголовке и области его действия.

По отношению к объявлению переменной в заголовке оператора цикла for, правило соотнесения гласит, что область действия имени, объявленного в операторе инициализации цикла for, располагается в блоке, содержащем данный оператор цикла for.

А вот область действия имени переменной j при этом остаётся прежней.

В теле оператора for может быть определена одноимённая переменная:

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

{

int i = 0; i += i;

}

Пространство имени переменной в операторе цикла ограничено блоком из двух операторов. В этом пространстве переменная, объявленная в заголовке, оказывается скрытой одноимённой переменной.

Десять раз переменная i из оператора-инициализатора цикла будет заслоняться одноимённой переменной из оператора тела цикла. И всякий раз к нулю будет прибавляться нуль.

Ещё один пример. Два расположенных друг за другом оператора цикла for содержат ошибку

for (int i = 0, int j = 0; i < 100; i++, j--)

{

// Операторы первого цикла.

}

for (int i = 0, int k = 250; i < 100; i++, k--)

{

// Операторы второго цикла.

}

Всё дело в том, что, согласно правилу соотнесения имён и областей действия имён в операторе цикла for, объявления переменных в заголовке цикла оказываются в общем пространстве имён. А почему, собственно, не приписать переменные, объявленные в заголовке цикла блоку, составляющему тело цикла? У каждого из альтернативных вариантов соотнесения имеются свои достоинства и недостатки. Однако выбор сделан, что неизбежно ведёт к конфликту имён и воспринимается как попытка переобъявления ранее объявленной переменной.

Эту самую пару операторов for можно переписать, например, следующим образом:

for (int i = 0, int j = 0; i < 100; i++, j--)

{

// Здесь располагаются операторы первого цикла.

}

for (i = 0, int k = 250; i < 100; i++, k--)

{

// Здесь располагаются операторы второго цикла.

}

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

for (i = 0, int k = 250; i < 100; i++, k--)

{

// Здесь располагаются операторы второго цикла.

}

for (int i = 0, int j = 0; i < 100; i++, j--)

{

// Здесь располагаются операторы первого цикла.

}

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

int i, j, k;

:::::

for (i = 0, k = 250; i < 100; i++, k--)

{

// Здесь располагаются операторы второго цикла.

}

for (i = 0, j = 0; i < 100; i++, j--)

{

// Здесь располагаются операторы первого цикла.

}

А вот ещё один довольно странный оператор цикла, в котором, тем не менее, абсолютно корректно соблюдены принципы областей действия имён, областей видимости имён, а также соглашения о соотнесении имён и областей их действия:

for (int x; x < 10; x++) {int x = 0; x++;}

Так что не забываем о том, что область действия имён в заголовке цикла шире от области действия имён в теле цикла. И вообще, если можно, избавляемся от объявлений в заголовке оператора цикла.

Оператор цикла do … while называется оператором цикла с постусловием. От циклов с предусловием он отличается тем, что сначала выполняется оператор (возможно, составной), а затем проверяется условие выполнения цикла, представленное выражением, которое располагается в скобках после ключевого слова while. В зависимости от значения этого выражения возобновляется выполнение оператора. Таким образом, всегда, по крайней мере, один раз, гарантируется выполнение оператора цикла.

int X=0;

do {cout << X << endl; X++;} while (X<0);

В большинстве случаев инсрукцию for можно представить при помощи инструкции while:

начальная_инструкция;

while (условие) {

инструкция;

выражение;

}

следующая_инструкция;

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

for (i = 1, sum = 0 ; ; sum += i++ )

cout << sum << endl;

Размещение точки с запятой сразу после правой закрывающей скобки заголовка for делает тело структуры пустым оператором. Обычно это логическая ошибка.

“Приращение” инструкции for может быть отрицательным (в этом случае в действительности происходит не приращение, а уменьшение переменной, управляющей циклом).

Если условие продолжения цикла с самого начала не удовлетворяется, то операторы тела инструкции for не выполняются и управление передается оператору, следующему за for.

Управляющая переменная иногда печатается или используется в вычислениях в теле инструкции for, но обычно это делается без изменений ее величины. Чаще управляющая переменная используется только для контроля числа повторений и никогда не упоминается в теле инструкции.

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

Давайте рассмотрим несколько вариантов применения цикла for:

а) Изменение управляющей переменной от 1 до 100 с шагом 1.

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

b) Изменение управляющей переменной от 100 до 1 с шагом -1

(с уменьшением на 1).

for (int i = 100; i >= 1; i--)

Распространенная ошибка при программировании, это использование несоответствующей операции отношения в условии продолжения цикла при счете циклов сверху вниз (например, использование i <= 1 при счете циклов сверху до 1 не включая).

c) Изменение управляющей переменной от 7 до 77 с шагом 7.

for (int i = 0; i <= 77; i += 7)

d) Изменение управляющей переменной от 20 до 2 с шагом -2.

for (int i = 20; i >= 2; i -= 2)

e) Изменение управляющей переменной в следующей последовательности:

2, 5, 8, 11, 14.

for (int j = 2;j <= 14; j += 3)

f) Изменение управляющей переменной в следующей последовательности:

99, 88, 77, 66, 55, 44, 33, 22, 11, 0.

for (int j = 99; j >= 0; j -= 11)