- •Р. Лафоре
- •Глава 1. Общие сведения 32
- •Глава 3. Циклы и ветвления 92
- •Глава 4. Структуры 142
- •Глава 5. Функции 168
- •Глава 6. Объекты и классы 217
- •Глава 7. Массивы и строки 261
- •Глава 8. Перегрузка операций 312
- •Глава 9. Наследование 361
- •Глава 10. Указатели 411
- •Глава 11. Виртуальные функции 476
- •Глава 12. Потоки и файлы 536
- •Глава 13. Многофайловые программы 596
- •Глава 14. Шаблоны и исключения 640
- •Глава 15. Стандартная библиотека шаблонов (stl) 681
- •Глава 16. Разработка объектно-ориентированного по 752
- •Глава 1 «Общие сведения» включает список тем, касающихся uml, с указа- нием их расположения в книге.
- •Глава 1
- •Глава 2
- •Глава 3
- •If внутри циклов
- •If и else во вложенных ветвлениях
- •Глава 4
- •Глава 5 Функции
- •Глава 6
- •Глава 7
- •123456. Россия
- •123456. Россия
- •Глава 8
- •Глава 9
- •Глава 10 Указатели
- •Main() передает адрес переменной var в ptrd в centimize()
- •Centimize() использует этот адрес для доступа к var
- •Глава 11
- •Глава 12
- •Тип:менеджер Фамилия: Александров Номер:1111
- •Тип:Ученый Фамилия: Лебедев Номер:2222
- •Тип:рабочий Фамилия:Шевелев Номер:3333
- •Глава 13
- •Глава 14
- •Много объектов разных классов в памяти Рис. 14.2. Шаблон класса
- •Алгоритмы используют итераторы для работы с объектами контейнеров. Рис. 15.1. Контейнеры, алгоритмы и итераторы
- •Глава 16
- •Глава 1
- •Глава 2
- •Глава 3
- •Глава 4
- •Глава 5
- •Глава 6
- •Глава 7
- •Глава 8
- •Глава 9
- •Глава 10 Ответы на вопросы
- •Глава 11
- •Глава 12 Ответы на вопросы
- •Глава 13 Ответы на вопросы
- •Глава 14 Ответы на вопросы
- •Глава 15 Ответы на вопросы
- •Глава 16
Циклы
и ветвления
Операции
отношения
Циклы
Ветвления
Логические
операции
Приоритеты
операций C++
Другие
операторы перехода
Лишь немногие из
программ выполняются последовательно
от первого операто-
ра к последнему.
Как и большинство людей, программы
определяют порядок
своих действий
в зависимости от меняющихся обстоятельств.
В программе преду-
смотрены переходы
из одной части программы в другую в
зависимости от выпол-
нения или
невыполнения некоторого условия.
Операторы, реализующие подоб-
ные
переходы, называются
условными операторами.
Условные операторы делятся
на две
основные категории:
циклы
и
ветвления.
Количество выполнений
цикла, а также выполнение или невыполнение
оп-
ределенной части программы
зависит от истинности или ложности
вычисля-
емого выражения. Как правило,
такие выражения содержат особый тип
операций,
называемых
операциями отношения,
сравнивающими два значения. Поскольку
и
циклы, и ветвления тесно связаны с
операциями отношения, то в первую
оче-
редь мы займемся рассмотрением
последних.
Операции отношения
Операция отношения
сравнивает между собой два значения.
Значения могут
быть как стандартных
типов языка C++,
например
char,
int
или
float,
так и
типов,
определяемых пользователем,
как мы позже убедимся. Сравнение
устанавливает
одно из трех возможных
отношений между переменными:
равенство, больше
или
меньше.
Результатом сравнения является значение
истина
или
ложь.
Например,
две величины могут быть
равны (истина)
или не равны (ложь).Глава 3
Наш первый пример
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
