Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лафоре Р. - Объектно-ориентированное программир...doc
Скачиваний:
50
Добавлен:
01.04.2025
Размер:
40.77 Mб
Скачать

Глава 3

Циклы и ветвления

  • Операции отношения

  • Циклы

  • Ветвления

  • Логические операции

  • Приоритеты операций C++

  • Другие операторы перехода

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

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

Операции отношения

Операция отношения сравнивает между собой два значения. Значения могут быть как стандартных типов языка C++, например char, int или float, так и типов, определяемых пользователем, как мы позже убедимся. Сравнение устанавливает одно из трех возможных отношений между переменными: равенство, больше или меньше. Результатом сравнения является значение истина или ложь. Например, две величины могут быть равны (истина) или не равны (ложь).

Наш первый пример RELAT демонстрирует использование операций сравне- ния применительно к целым переменным и константам.

// relat.cpp

// применение операций отношения #include <iostream> using namespace std;

int main() {

int numb;

cout << "Введите число: "; cin >> numb;

cout << "numb < 10 равно " << (numb < 10) << endl; cout << "numb > 10 равно " << (numb > 10) << endl; cout << "numb == 10 равно " << (numb == 10) << endl; return 0;

}

Эта программа использует три вида сравнения числа 10 с числом, вводимым пользователем. Если пользователь введет значение, равное 20, то результат ра- боты программы будет выглядеть так:

Введите число: 20 numb < 10 равно 0 numb > 10 равно 1 numb == 10 равно 0

Первое выражение истинно в том случае, если значение numb меньше, чем 10; второе — тогда, когда numb больше, чем 10; и наконец, третье — когда numb рав- но 10. Как можно видеть из результата работы программы, компилятор C++ присваивает истинному выражению значение 1, а ложному — значение 0.

Как мы упоминали в предыдущей главе, стандартный C++ включает в себя тип bool, переменные которого имеют всего два значения: true и false. Возможно, вы подумали о том, что результаты сравнения выражений должны иметь тип bool, и, следовательно, программа должна выводить false вместо 0 и true вместо 1, но C++ интерпретирует true и false именно как 1 и 0. Это отчасти объясняется историческими причинами, поскольку в языке C не было типа bool, и наиболее приемлемым способом представить ложь и истину представлялись именно числа 0 и 1. С введением типа bool два способа интерпретации истинности и ложности объединились, и их можно представлять как значениями true и false, так и зна- чениями 1 и 0. В большинстве случаев не важно, каким из способов пользовать- ся, поскольку нам чаще приходится использовать сравнения для организации циклов и ветвлений, чем выводить их результаты на экран.

Полный список операций отношения в C++ приводится ниже.

Операция

Название

>

больше

<

меньше

==

равно

!=

не равно

>=

больше или равно

<=

меньше или равно

Теперь рассмотрим выражения, использующие операции сравнения, и значе- ния, получающиеся в результате вычисления таких выражений. В первых двух строках примера, приведенного ниже, присваиваются значения переменным harry и jane. Далее вы можете, закрыв комментарии справа, проверить свое умение определять истинность выражений.

jane = 44; // оператор присваивания

harry = 12; // оператор присваивания

(jane == harry) // ложь

(harry <= 12) // истина

(jane > harry) // истина

(jane >= 44) // истина

(harry != 12) // ложь

(7 < harry) // истина

(0) // ложь (по определению)

(44) // истина (поскольку не ноль)

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

Несмотря на то, что C++ использует 1 для представления истинного значе- ния, любое отличное от нуля число будет воспринято им как истинное. Поэтому истинным будет считаться и последнее выражение в нашем примере.

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

Циклы

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

В C++ существует 3 типа циклов: for, while и do.

Цикл for

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

Цикл for организует выполнение фрагмента программы фиксированное чис- ло раз. Как правило (хотя и не всегда), этот тип цикла используется тогда, когда число раз, за которое должно повториться исполнение кода, известно заранее.

В примере FORDEMO, приведенном ниже, выводятся на экран квадраты целых чисел от 0 до 14:

// fordemo.cpp

// демонстрирует работу простейшего цикла for #include <iostream> using namespace std;

int main() {

int j; // определение счетчика цикла

for(j = 0; j < 15; j++) // счетчик меняется от 0 до 14

cout << j * j << " "; // квадрат значения j выводится на экран

cout << endl;

return 0;

}

Результат работы программы выглядит так:

0 1 4 9 16 25 36 49 64 81 100 121 144 169 196

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

for(j = 0; j < 15; j++)

Первое из трех выражений называют инициализирующим, второе — условием проверки, а третье — инкрементирующим, как показано на рис. 3.1.

Рис. 3.1. Синтаксис цикла for

Эти три выражения, как правило (по не всегда), содержат одну переменную, которую обычно называют счетчиком цикла. В примере FORDEMO счетчиком цик- ла является переменная j. Она определяется до того, как начнет исполняться те- ло цикла.

Под телом цикла понимается та часть кода, которая периодически испол- няется в цикле. В нашем примере тело цикла состоит из единственного опе- ратора:

cout << j * j << " ";

Данный оператор печатает квадрат значения переменной j и два пробела после него. Квадрат находится как произведения переменной j самой на себя. Во время исполнения цикла переменная j принимает значения 0, 1, 2, 3 и т. д. до 14, а выводимые значения квадратов соответственно 0, 1, 4, 9, ..., 196.

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

Рассмотрим, каким образом три выражения, стоящие в круглых скобках опе- ратора for, влияют на работу цикла.

Инициализирующее выражение

Инициализирующее выражение вычисляется только один раз — в начале выпол- нения цикла. Вычисленное значение инициализирует счетчик цикла. В примере FORDEMO переменная j получает значение 0.

Условие выполнения цикла

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

cout << endl;

Инкрементирующее выражение

Инкрементирующее выражение предназначено для изменения значения счетчи- ка цикла. Часто такое изменение сводится к инкрементированию счетчика. Мо- дификация счетчика происходит после того, как тело цикла полностью выпол- нилось. В нашем примере увеличение j на единицу происходит каждый раз после завершения тела цикла.

Блок-схема, иллюстрирующая исполнение цикла for, приведена на рис. 3.2.

Рис. 3.2. Исполнение цикла for

Число выполнений цикла

В примере FORDEMO цикл выполняется 15 раз. В первый раз он выполняется при нулевом значении j. Последнее исполнение цикла произойдет при j = 14, поскольку условием выполнения цикла служит j < 15. Когда j принимает значение, равное 15, выполнение цикла прекращается. Как правило, подобную схему исполнения применяют в том случае, когда необходимые действия нужно выполнить фик- сированное количество раз. Присваивая счетчику начальное значение, равное 0, в качестве условия продолжения цикла ставят сравнение счетчика с желаемым числом выполнений и увеличивают счетчик на единицу каждый раз, когда ис- полнение тела цикла завершается. Например, цикл

for(count = 0; count < 100; count++) // тело цикла

будет выполнен 100 раз, а счетчик count будет принимать значения от 0 до 99.

Несколько операторов в теле цикла

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

Следующий пример с названием CUBELIST демонстрирует использование не- скольких операторов в теле одного цикла. Программа возводит в куб числа от 1 до 10 и печатает результаты в двух столбцах.

// cubelist.cpp

// подсчет кубов целых чисел от 1 до 10 #include <iostream>

#include <iomanip> // для setw

using namespace std;

int main() {

int numb; // счетчик цикла

for(numb = 1; numb <= 10; numb++) // цикл от 1 до 10 {

cout << setw(4) << numb; // вывод первого столбца

int cube = numb * numb * numb; // вычисление куба cout << setw(6) << cube << endl; // вывод второго столбца

}

return 0;

}

Результат работы программы выглядит следующим образом:

1 1

2 8

3 27

4 64

5 125

6 216

7 343

8 512

9 729

10 1000

Мы показали, что оператор цикла совсем не обязательно использовать так, как мы делали в предыдущем примере: начальное значение у счетчика здесь 1, а не 0; увеличение счетчика происходит до 10, а не до 9, а условие проверки со- держит операцию сравнения «меньше или равно» <=. Таким образом, цикл ис- полняется 10 раз, а счетчик пробегает значения от 1 до 10 (а не от 0 до 9).

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

Блоки и область видимости переменных

Тело цикла, заключенное в фигурные скобки, называется блоком. Важной особен- ностью блока является то, что переменные, определенные внутри него, невидимы вне этого блока. Невидимость означает, что программа не имеет доступа к пере- менной (мы подробнее остановимся на понятии видимости в главе 5 «Функции»). В примере CUBELIST мы определяем переменную cube внутри блока:

int cube = numb * numb * numb;

Получить доступ к этой переменной вне блока невозможно — она видима лишь внутри фигурных скобок. Если вы попытаетесь присвоить переменной cube значение вне блока:

cube = 10;

то компилятор выдаст сообщение о том, что переменная с именем cube не опре- делена.

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

Форматирование и стиль оформления циклов

Хороший стиль программирования предполагает сдвиг тела цикла вправо относительно оператора, управляющего циклом, и относительно остального программного кода. В программе FORDEMO такой сдвиг применен к одной строке, а в программе CUBELIST вправо сдвинут весь блок, за исключением обрамляющих фигурных скобок. Подобное форматирование является очень удобным, посколь- ку позволяет легко увидеть, где начинается цикл, а где заканчивается. Компиля- тор не отличает форматированный текст от неформатированного (по крайней мере, на его работе это никак не сказывается).

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

for(numb = 1; numb <= 10; numb++){ cout << setw(4) << numb; int cube = numb * numb * numb;

cout << setw(6) << cube << endl; }

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

for(numb = 1; numb <= 10; numb++) {

cout << setw(4) << numb; int cube = numb * numb * numb;

cout << setw(6) << cube << endl; }

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

Обнаружение ошибок

С помощью средств компилятора, позволяющих облегчить процесс обнаружения ошибок в программах, вы можете создать динамическую модель, иллюстриру- ющую процесс выполнения вашего цикла. Главным из таких средств является пошаговое выполнение. Откройте окно проекта для отлаживаемой программы и ок- но с текстом программы. Детали работы с отладчиком зависят от компиляторов, информацию о которых можно получить из приложения В «Microsoft Visual C++» или приложения Г «Borland C++ Builder». Нажимая соответствующую функцио- нальную клавишу, можно построчно исполнять код вашей программы. Таким образом, вы сможете увидеть работу программы в том порядке, в котором запи- саны ваши операторы. При работе с циклом вы сможете убедиться в том, что сначала исполняется тело вашего цикла, затем происходит переход, и тело цикла исполняется снова.

Отладчик можно также использовать для того, чтобы следить за значениями переменных в процессе исполнения программы. Вы можете поэкспериментиро- вать с программой cubelist, поместив переменные numb и cube в окно Watch window вашего отладчика, и посмотреть на изменения их значений при испол- нении программы. Чтобы получить информацию об использовании окна Watch, загляните в соответствующее приложение.

Watch window и пошаговое исполнение программы являются мощным отла- дочным инструментом. Если поведение вашей программы отличается от задуман- ного, вы можете использовать эти средства для контроля над объектами про- граммы. Как правило, причина ошибки после такой отладки становится ясной.

Варианты цикла for

Инкрементирующий оператор не обязательно должен производить операцию инкрементирования счетчика цикла; вместо инкрементирования может исполь- зоваться любая другая операция. В следующем примере под названием FACTOR в операторе цикла используется декрементирование счетчика цикла. Программа запрашивает значение у пользователя, а затем подсчитывает факториал этого числа (факториал числа представляет из себя произведение всех целых положи- тельных чисел, не превышающих данное число. Например, факториал числа 5 равен 1*2*3*4*5 = 120).

// factor.cpp

// подсчет факториала числа с помощью цикла for #include <iostream> using namespace std; int main()

{

unsigned int numb;

unsigned long fact = 1; // тип long для результата

cout << "Введите целое число: ";

cin >> numb; // ввод числа

for(int j = numb; j > 0; j--) // умножение 1 на

fact *= j; // numb, numb-1, ..., 2, 1

cout << "Факториал числа равен " << fact << endl; return 0;

}

В этом примере инициализирующий оператор присваивает переменной j зна- чение, вводимое пользователем. Условием продолжения цикла является поло- жительность значения j. Инкрементирующее выражение после каждой итера- ции уменьшает значение j на единицу.

Мы использовали тип unsigned long для переменной, хранящей значение фак- ториала, потому, что даже для небольших чисел значения их факториалов очень велико. В 32-битных системах размеры типов int и long совпадают, но в 16-бит- ных системах размер типа long больше. Следующий результат работы програм- мы показывает, насколько велико может быть значение факториала даже для не- большого числа:

Введите целое число: 10 Факториал числа равен 3628800

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

Определение счетчика цикла внутри оператора цикла for

В последней программе есть еще одно полезное нововведение: переменная j опи- сана прямо внутри оператора цикла:

for(int j = numb; J > 0; j--)

Подобная конструкция является типичной для C++, и, как правило, наибо- лее удобна для работы со счетчиками цикла. Такое определение переменной стоит наиболее близко к месту ее употребления. Переменная, описанная в опе- раторе цикла, видна только внутри этого цикла (компилятор Microsoft делает такие переменные видимыми от точки объявления до конца программы, но это не является стандартом C++).

Несколько инициализирующих выражений и условий цикла

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

for(j = 0, alpha = 100; j < 50; j++, beta--) {

// тело цикла }

У данного цикла есть обычный счетчик в виде переменной j, но в операторе цикла, помимо j, также инициализируется переменная alpha и декрементируется переменная beta. Переменные alpha и beta никак не связаны ни друг с другом, ни с переменной j. При использовании нескольких инициализирующих или инкре- ментирующих выражений необходимо разделять их запятыми.

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

for(; ;)

эквивалентна циклу while с условием продолжения, равным true. Мы рассмот- рим циклы while чуть позже.

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

Цикл while

Цикл for выполняет последовательность действий определенное количество раз. А как поступить в том случае, если заранее не известно, сколько раз понадобится выполнить цикл? Для этого разработан другой вид цикла — while.

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

// endon0.cpp // применение цикла WHILE #include <iostream> using namespace std;

int main() {

int n = 99; // n не должна быть равна 0 перед началом цикла

while(n != 0) // цикл, пока значение n не равно 0

cin >> n; // считывание n с клавиатуры

cout << endl;

return 0;

}

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

1

27

33

144

9

0

Внешне цикл while напоминает упрощенный вариант цикла for. Он содержит условие для продолжения цикла, но не содержит ни инициализирующих, ни ин- крементирующих выражений. Синтаксис цикла while показан на рис. 3.3.

Рис. 3.3. Синтаксис цикла while

До тех пор пока условие продолжения цикла выполняется, исполнение тела цикла продолжается. В примере ENDON0 значение выражения

n != 0

истинно до тех пор, пока пользователь не введет ноль.

На рис. 3.4 показан механизм работы цикла while. На самом деле он не так прост, как кажется вначале. Несмотря на отсутствие инициализирующего опе- ратора, нужно инициализировать переменную цикла до начала исполнения тела цикла. Тело цикла должно содержать оператор, изменяющий значение перемен- ной цикла, иначе цикл будет бесконечным. Таким оператором в цикле из при- мера ENDON0 является cin >> n;

Рис. 3.4. Исполнение цикла while

Несколько операторов в цикле while

Следующий пример, WHILE4, демонстрирует применение нескольких операторов в теле цикла while. Это немного модифицированная версия программы CUBELIST, которая вычисляет не третьи, а четвертые степени последовательности целых чисел. Поставим дополнительное условие к задаче: все выводимые значения должны иметь размер не более 4 символов, то есть необходимо завершить вы- полнение цикла, когда результат превысит 9999. Без предварительного расчета мы не знаем, какое число будет источником такого результата, поэтому возло- жим определение этого числа на нашу программу. Условие продолжения цикла будет сформировано так, что программа завершится до того, как результаты пре- высят установленный барьер.

// while4.cpp

// возведение в четвертую степень целых чисел #include <iostream>

#include <iomanip> // для setw

using namespace std;

int main() {

int pow = 1; // первое возводимое число равно 1

int numb = 1; // 1 в 4-й степени равна 1

while(pow < 10000) // цикл, пока в степени не более 4 цифр

{

cout << setw(2) << numb; // вывод числа

cout << setw(5) << pow << endl; // и его 4-й степени ++numb; // инкремент текущего числа

pow = numb * numb * numb * numb; // вычисление 4-й степени

}

cout << endl; return 0;

}

Для того чтобы найти значение четвертой степени числа, мы просто умножа- ем это число само на себя четырежды. После каждой итерации мы увеличиваем значение переменной numb на единицу, но нам не нужно использовать значение numb в операторе цикла while, поскольку выполнение цикла зависит только от значения результирующей переменной pow. Результат работы программы вы- глядит так:

1 1

2 16

3 81

4 256

5 625

6 1296

7 2401

8 4096

9 6561

Следующее значение — 10 000 — будет слишком велико для вывода в четыре позиции, но к этому времени уже будет произведен выход из программы.

Приоритеты арифметических операций и операций отношения

Следующая программа затронет вопрос старшинства операций. В этой програм- ме генерируется последовательность чисел Фибоначчи. Первыми членами такой последовательности являются числа

1 1 2 3 5 8 13 21 34 55

Каждый новый член получается путем сложения двух предыдущих: 1 + 1 = 2, 1 + 2 = 3, 2 + 3 = 5, 3 + 5 = 8 и т. д. Числа Фибоначчи проявляют себя в таких различных ситуациях, как методы сортировки и подсчет числа спиралей у цвет- ков подсолнуха.

Одним из наиболее интересных применений чисел Фибоначчи является их связь с так называемым «золотым сечением». Золотое сечение — это идеальные пропорции в архитекtype и искусстве, воплощенные при строительстве древне- греческих храмов. Чем больше номера членов последовательности чисел Фибо- наччи, тем ближе отношение последних двух членов к золотому сечению. Текст программы FIBO приведен ниже.

// fibo.cpp

// генерирование чисел Фибоначчи с помощью цикла while #include <iostream> using namespace std;

int main() {

const unsigned long limit = 4294967295; // граница типа unsigned long unsigned long next = 0; // предпоследний член unsigned long last = 1; // последний член

while(next < limit / 2) // результат не должен быть слишком большим {

cout << last << " "; // вывод последнего члена long sum = next + last;// сложение двух последних членов next = last; // обновление предпоследнего

last = sum; // и последнего членов

}

cout << endl;

return 0; }

Вывод программы выглядит следующим образом:

1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946 17711 28657 46368 75025 121393 196418 317811 514229 832040 1346269 2178309 3524578 5702887 92274655 14930352 24157817 39088169 63245986 102334155 165580141 267914296 433494437 701408733 1134903170 1836311903 2971215073

Отношение последних двух членов последовательности равно 0.618033988 - что очень близко к «золотому сечению».

В программе FIBO используется тип unsigned long с максимальным среди це- лых типов диапазоном представления положительных чисел. Условие, прове- ряемое перед началом исполнения тела цикла, выводит программу из цикла до

того, как произойдет переполнение. Мы определяем величину, равную предель- ному значению переменной типа unsigned long, как константу, поскольку эта ве- личина не меняется в ходе выполнения программы. Цикл должен прекратиться в том случае, если значение переменной next станет больше половины допусти- мой для данного типа границы. Значение переменной sum может достигать лю- бых допустимых значений для данного типа. Условие продолжения цикла со- держит две операции:

(next < limit / 2)

Нам необходимо сравнить значение next с limit/2, а значит, деление должно произойти перед сравнением. Для того чтобы быть уверенными в том, что про- изойдет именно это, мы можем использовать круглые скобки:

(next < (limit / 2))

На самом деле скобки не нужны. Почему? Потому что арифметические опе- рации имеют более высокий приоритет, чем операции отношения. Таким обра- зом, мы можем быть уверенными в том, что деление имеет более высокий при- оритет, нежели операция «больше», и будет выполнено первым. Мы рассмотрим старшинство операций в полном объеме после того, как расскажем о логических операциях.

Цикл do

В цикле while условие продолжения выполнения цикла помещалось в начало цикла. Это означало, что в случае невыполнения условия при первой проверке тело цикла вообще не исполнялось. В некоторых случаях это целесообразно, но возможны и ситуации, когда необходимо выполнить тело цикла хотя бы один раз вне зависимости от истинности проверяемого условия. Для этого следует ис- пользовать цикл do, в котором условие продолжения цикла располагается не пе- ред, а после тела цикла.

Наш следующий пример DIVDO выводит приглашение ввести два числа: дели- мое и делитель, а затем производит целочисленное деление с использованием операций / и % и выводит полученные частное и остаток.

// divdo.cpp // применение цикла do #include <iostream> using namespace std;

int main() {

long dividend, divisor; char ch;

do // начало цикла do

{ // действия

cout << "Введите делимое: "; cin >> dividend; cout << "Введите делитель: "; cin >> divisor; cout << "Частное равно " << dividend / divisor; cout << ", остаток равен " << dividend % divisor;

cout << "\nЕще раз?(y/n): ";

cin >> ch; }

while(ch != 'n'); // условие цикла return 0;

}

Большая часть программы находится в составе тела цикла do. Ключевое сло- во do обозначает начало цикла. Затем, как и в других циклах, следует тело, об- рамленное фигурными скобками. Завершает цикл условие продолжения, описы- ваемое с помощью ключевого слова while. Это условие похоже на условие цикла while, но у него есть два отличия: оно располагается в конце цикла и завершает- ся точкой с запятой (;). Синтаксис цикла do показан на рис. 3.5.

Перед тем как производить вычисление, программа DIVDO спрашивает поль- зователя, хочет ли он произвести это вычисление. Если в ответ программа полу- чает символ 'y', то выражение

ch != 'n'

сохраняет значение true. В случае, если пользователь вводит 'n', условие продол- жения цикла не выполняется и происходит выход из цикла. На рис. 3.6 приве- дена схема функционирования цикла do.

Вот пример возможного вывода программы DIVDO:

Введите делимое: 11

Введите делитель: 3

Частное равно 3, остаток равен 2

Еще раз? (y/n): у

Введите делимое: 222

Введите делитель: 17

Частное равно 13, остаток равен 1

Еще раз? (y/n): n

Рис. 3.5. Синтаксис цикла do

Рис. 3.6. Исполнение цикла do

Выбор типа цикла

Мы рассмотрели основные аспекты использования циклов. Цикл for подходит для тех случаев, когда мы заранее знаем, сколько раз нам потребуется его выпол- нение. Циклы while и do используются в тех случаях, когда число итераций цик- ла заранее не известно, причем цикл while подходит в тех случаях, когда тело цикла может быть не исполненным ни разу, а цикл do — когда обязательно хотя бы однократное исполнение тела цикла.

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

Ветвления

Управление циклом всегда сводится к одному вопросу: продолжать выполнение цикла или нет? Разумеется, люди в реальной жизни встречаются с гораздо более разнообразными вопросами. Нам нужно решать не только, пойти ли на работу сегодня или нет (продолжить ли цикл), но и делать более сложный выбор, на- пример, купить ли нам красную футболку или зеленую (или вообще не покупать футболку) или взять ли нам отпуск и, в случае положительного ответа, провести его в горах или на море?

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

В C++ существует несколько типов ветвлений, наиболее важным из которых является if...else, осуществляющее выбор между двумя альтернативами. В опе- раторе ветвления if...else использование else не является обязательным. Для вы- бора одной из множества альтернатив используется оператор ветвления switch, действие которого определяется набором значений соответствующей перемен-

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

Оператор if является наиболее простым из операторов ветвлений. Следующая программа, IFDEMO, иллюстрирует применение оператора if.

// ifdemo.cpp

// применение оператора if #include <iostream> using namespace std;

int main() {

int x;

cout << "Введите число: "; cin >> x; if(x > 100)

cout << "Это число больше, чем 100\n "; return 0;

}

За ключевым словом if следует условие ветвления, заключенное в круглые скобки. Синтаксис оператора if показан на рис. 3.7. Легко заметить, что синтак- сис if очень напоминает синтаксис while. Разница заключается лишь в том, что если проверяемое условие окажется истинным, то операторы, следующие за if, будут выполнены всего один раз; операторы, следующие за while, исполняются до тех пор, пока проверяемое условие не станет ложным. Функционирование оператора if показано на рис. 3.8.

Примером работы программы IFDEMO может служить следующий:

Введите число: 2000 Это число больше, чем 100

Если вводимое число окажется не превосходящим 100, то программа завер- шится, не напечатав вторую строку.

Условный оператор if

Рис. 3.7. Синтаксис оператора if