Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Штерн В. - Основы C++. Методы программной инженерии - 2003

.pdf
Скачиваний:
238
Добавлен:
13.08.2013
Размер:
28.32 Mб
Скачать

щ 120 I

Часть I ^ Введение в орогрог^штрование на С-^-^

Листинг.4Л1 показывает реализацию цикла с контрольным значением О или отрицательным числом.

Листинг 4.11. Реализация цикла while с отрицательным или нулевым контрольным значением

#inclucle <iostream> using namespace std;

int main ()

{

double total, amount; int count;

 

 

// разная

инициализация

total = 0.0; count = 0;

 

 

 

amount =1.0;

 

 

 

 

// искусственный прием: почему 1, а не 10?

while (amount > 0)

 

 

 

// вычисление текущих данных

{

cout «

"Введите количество

(для завершения - О или отрицательное число): ";

 

cin » amount;

.

 

 

// ввод текущих данных

 

total += amount;

 

 

 

// обработка текущих данных

cout «

count++;

}

 

 

 

 

 

 

 

"\пСумма по " « count « "транзакциям равна "«total « endl;

 

return 0;

 

 

 

 

 

 

 

 

 

 

В листинге 4.10 цикл продолжается до тех пор, пока count не превысит значе­

 

ния 5. Перед первым проходом цикла count равно 1, перед вторым — 2, перед

 

пятым — 5, а

после пятого,

когда count <= 5 принимает

значение false, оно

 

равно 6. Для программы из листинга 4.11 это не подходит. Здесь нужно, чтобы

 

в конце выполнения значение count отражало число обработанных элементов.

 

Вот почему count в листинге 4.11 инициализируется значением О, а не 1.

 

 

Программист, использующий C + +

(а на самом деле — любой программист),

 

должен продумать этот вопрос при написании циклов. Корректны ли начальные

 

значения? Обеспечивают ли они завершение цикла? Вот почему в данном примере

 

число элементов так мало: это позволяет легко отследить итерации цикла. Вывод

 

программы из листинга 4.11 показан на рис. 4.18.

 

 

 

Введите количество (для завершения - 0 или отрицательное число): 22

 

 

Введите

количество

(для

завершения

- 0 или отрицательное

число): 33

 

 

Введите

количество

(для

завершения

- 0 или отрицательное

число): 44

 

 

Введите

количество

(для

завершения

- 0 или отрицательное

число): -1

 

 

Сумма ПС

4 транзакциям

равна 98

 

 

 

 

Рис. 4.18. Вывод программы

из листинга

4.11

 

 

 

с отрицательным

контрольным

значением

Но ведь число транзакций здесь некорректно! Перед тем как пользователь ввел -1.0, значение count было равно 3, и это правильно. После ввода -1.0 оно стало равно 4, что уже неправильно. Более того, это отрицательное число также добавляется к total и общая сумма тоже некорректна.

Такие технические проблемы можно решить несколькими способами, напри­ мер, инициализировать счетчик значением -1 или уменьшать его после цикла. То же самое можно сделать с суммой total. Пусть код после цикла выглядит так:

count-;

t o t a l

-= amount;

/ / коррекция после цикла

cout «

"\пСумма по " « count «

" транзакциям равна "

« t o t a l «

endl;

 

Глава 4 • Управление xoAOivi выполнения прогромг^ы C^^-i-

121

Не очень элегантное решение, но оно работает. Другой вариант заключается в добавлении в середину цикла условного оператора и изменении значений total и count, когда значение amount отличается от контрольного:

while

(amount > 0)

/ /

вычисление текущих данных

{ cout «

" Введите количество (отрицательное число или О - для завершения): ";

cin »

amount;

/ /

введите текущие данные

i f

(amount > 0)

/ /

проверка конца данных

 

{

t o t a l += amount;

/ /

обработка текущих данных

 

 

count++; } }

 

 

Как можно видеть, эти исправления устраняют проблемы за счет увеличения сложности кода. Не очень элегантно и часто (но не всегда) свидетельствует о про­ явлении концептуальной проблемы. И в самом деле, в решении, представленном в листинге 4.11, есть еш,е одна проблема, не техническая, а концептуальная. Проблема первого прохода цикла. Когда выделяется память для переменных C-f+ , она содержит случайные значения (не совсем, правда, но об этом позднее). В некоторых случаях при выполнении программы такое значение может быть равно 0. Это означает, что программа будет завершаться без обработки данных. Чтобы предотвратить такой эффект, можно инициализировать amount некоторым значением — просто для предотвраидения несвоевременного завершения цикла.

С точки зрения программной инженерии это некорректно. Здесь использует­ ся 1.0, что не имеет семантического смысла в контексте приложения. Если бы значение было равно 2.0, то результат был бы тем же. Данное значение не доносит до сопровождающего приложение программиста никакой мысли разработчика, а следовательно, только усложняет дело. Программист потратит какое-то время, пытаясь уяснить, что означает 1.0, прежде чем поймет, что ничего. Хорошо, если это займет немного времени. Все равно, такого рода огрехи только напрасно увеличивают сложность приложения.

Еи;е одна проблема с данным циклом в том, что контрольное значение не интерпретируется корректно. Когда пользователь вводит отрицательное число (или отрицательное значение поступает по коммуникационной линии), оно сначала добавляется к total и только после этого используется для завершения цикла.

Хорошее решение проблемы состоит в изменении структуры тела цикла. В ли­ стинге 4.11 тело цикла сначала считывает amount (это может быть контрольное значение) и обрабатывает его. Здесь предполагается, что предварительно нужно обработать введенное ранее (на предыдуидей итерации) значение amount, и только в конце цикла считывается amount для следующей итерации. Структура цикла может выглядеть так:

while (amount > 0)

/ /

оценка текущих данных

{ t o t a l

+= amount;

/ /

обработка текущих данных

count++;

 

 

cout «

"Введите количество (для завершения -

О или отрицательное число): ";

cin »

amount; }

/ /

изменение текущих данных

А как насчет первой итерации цикла? Значение

1.0,

использовавшееся в лис­

тинге 4.11, здесь не подходит. Следует ли инициализировать переменную значе­ нием О? Если О добавиться к total, вреда не будет. Это возможно, но цикл завершится при первой проверке — условие amount > О даст false.'KpoMc того, такое решение не будет работать, если нужно вывести значение amount, которое вводилось или обрабатывалось каким-то другим нетривиальным образом.

Хорошим решением здесь станет так называемый метод предварительного чтения. Первое значение считывается перед циклом, обрабатывается в начале цикла, затем в конце цикла считывается новое значение, которое обрабатывается в начале цикла на следующей итерации. Данное, решение показано в листин­ ге 4.12, а результаты представлены на рис. 4.19.

122

^\-'"»Л ;

: ^r%ornnf^Ammp€

 

 

^^^^-^ш>а^ш^^

Листинг 4.12. Реализация цикла while с предварительным чтением

#inclucle <iostream> using namespace std;

int main ()

{

double total, amount; int count;

total = 0.0; count = 0;

 

/ /

разная инициализация

cout «

"Введите количество (для завершения

О или отрицательное

число): ";

cin »

amount;

 

/ /

первый ввод текущих данных

while (amount > 0)

 

/ /

вычисление текущих данных

{ total += amount;

 

/ /

обработка текущих данных

count++;

 

 

 

 

cout

« "Введите количество

(для завершения

-'О или отрицательное число): ";

cin

»

amount; }

 

/ /

ввод текущих данных

cout

«

"\пСумма по " « count

« " транзакциям равна " « t o t a l

«

endl;

return

0;

 

 

 

 

Введите количество (для завершения - 0или отрицательное число): 22

1 Введите количество (для завершения - 0или отрицательное число): 33 Введите количество (для завершения •- 0или отрицательное число): 44

Введите количество (для завершения -- 0или отрицательное число): -1

Сумма ПС 3 транзакциям равна 99

Рис. 4 . 1 9 . Вывод программы

из листинга

4.12

с предварительным

чт,ением

 

Все проблемы (и необходимость их исправления) исчезли. Переменные count и total инициализируются своими начальными значениями (0). Переменная amount не инициализируется — ее начальное значение (каким бы оно ни было) заменяет­ ся при операции ввода. После цикла нет никакой постобработки, которая настраи­ вала бы некорректно измененные в цикле значения.

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

Прежде чем переходить к циклам do-while, следует проиллюстрировать неко­ торые моменты проектирования циклов while. Возьмем, например, потоковую об­ работку символов. Для простоты будем просто отображать символы на экране (эхо), подсчитывать их количество и число пробелов (если они есть). Обработка должна продолжаться, пока пользователь не нажмет клавишу Enter (символ Лп'). Будем использовать структуры цикла с предварительным чтением. Первый символ вводится перед циклом while, а в начале цикла на экране отображается введенный ранее символ. В ycJЮвии цикла проверяется, является ли следуюш^ий символ сим­ волом новой строки. Если нет (условие цикла равно true), то обработка продол­ жается. В начале цикла символ выводится на экран, подсчитывается, а в конце цикла считывается следуюндий символ. Если это символ новой строки, то условие цикла даст false и цикл завершится.

Для ввода символа применяется функция get() из библиотеки lost ream. Она передается как сообпдение объекту cin. О синтаксисе сообш,ений рассказывалось в главе 2, и теперь полезно им воспользоваться. Фактически нужно знать лишь, что cin. get О возвраш,ает следуюш,ий символ из буфера ввода.

Рис. 4.20.
Результаты выполнения программы из листинга 4.13 (обработка вводимых символов)
}
Наберите предложение и нажмите Enter Это проверка Это проверка
Общее число символов 15 Число пробелов равно 3

Глава 4 • Управление XOAOIVI выполнения программы C++

123

Листинг 4.13. Цикл while с предварительным чтением для получения символов

#inclucle <iostream> using namespace std;

int main

()

 

{

 

// инициализация счетчиков

char ch; int count = 0, spaces = 0;

cout «

"\пНаберите предложение и нажмите Enter\n";

ch = cin.getO;

// предварительное чтение для цикла

while (ch != '\n')

// нет точки с запятой после условия

{ cout « ch;

// обработка данных: эхо, проверка, подсчет

if (ch == ' ')

 

spaces++;

 

count++;

// смена текущих данных

ch = cin.getO; }

cout «

"\пОбщее число символов " « count «

endl;

cout «

"Число пробелов равно " « spaces «

endl;

return 0;

В листинге 4.13 показано решение данной проблемы, а на рис. 4.20 продемонстрированы результаты теста.

Здесь мы снова сталкиваемся с разницей между внеш­ ним видом и сутью веш,ей. Программа показывает, что первый введенный пользователем символ отображается перед вводом второго символа, а второй — перед вводом третьего и т. д. Но если выполнить программу, окажется, что символы не появятся на экране, пока не будет нажата клавиша Enter, после чего они отобразятся все сразу. Причина в том, что при вызове cin. get() происходит ввод не с клавиатуры, а из внутреннего буфера в память компь­ ютера. Когда пользователь нажимает клавиши на клавиа­

туре, данные поступают в буфер и становятся доступными программе только при нажатии Enter или при заполнении буфера. Применение буферов может повысить производительность программы при частом обмене небольшими порциями данных с файлом. При буферизации медленные операции ввода-вывода с внешним фай­ лом выполняются сразу для большого количества данных. (Сама операция занима­ ет практически одно и то же время, независимо от объема данных.) Кроме того, обмен с буфером при вводе данных осуш,ествляется намного быстрее (впрочем, для данной программы это не важно). Так что не удивляйтесь, если не увидите вывода при наборе данных.

Обратите внимание, что условие цикла while (ch != '\n') проверяется сразу за оператором ch = cin.getO. В первый раз это будет оператор перед циклом, а далее — операторы в конце цикла. Такая структура кода наводит на мысль об использовании известного стиля С+Н-: комбинировании присваивания и проверки условия, что показано в листинге 4.14.

Это очень популярный метод в C-f- + . В программе из листинга 4.12 нельзя было бы использовать оператор ввода (cin » amount;), поскольку он не возвра- ш,ает введенного пользователем значения. Он возвраш,ает значение, но это значе­ ние объекта cin, а не символ. Оператор ввода из листинга 4.13 (ch = cin.getO;) возвраш^ает значение символа и может использоваться в программе, показанной в листинге 4.14.

124

I

Часть i ^ Введение в прогротттрошаишв на С4-+

Листинг 4.14. Цикл while с присваиванием в условии цикла

#inclucle

<iostream>

 

using namespace std;

 

int

main

()

 

{

 

 

// инициализация счетчиков

char ch; int count = 0, spaces = 0;

cout «

"\пНаберите предложение и нажмите Enter\n";

while ((ch = cin.getO) != '\n')

// изменение текущих данных

{ cout « ch;

// обработка данных: эхо, проверка, подсчет

 

if (ch == ' ') spaces++;

// ОКдля одной строки

 

count++; }

endl;

cout «

"\пОбщее число символов " « count «

cout «

"Число пробелов равно " « spaces «

endl;

return 0;

}

Обратите внимание на круглые скобки, в которые заключен оператор ввода в листинге 4.14. Если их опустить, это не будет синтаксической ошибкой, но изме­ нится смысл кода:

cout

«

"\пНаберите предложение и нажмите Enter\n";

while

(ch = cin.getO != ' \ n ' )

/ / оператор ввода не заключен в скобки

{ cout «

ch;

 

i f

(ch

== ' ' )

 

spaces++;

 

count++; }

 

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

while (ch = (cin.getO != ' \ n ' ) / / совсем другая история

Здесь вводится символ, а затем он сравнивается с символом новой строки. Для всех символов (кроме последнего во вводимой строке) результатом будет true (они не являются символами новой строки), и переменная ch получает значение 1 (это непечатаемый код). Символы отображаются некорректно, а число пробелов в строке будет равно нулю.

Не следует жаловаться на неверный порядок операций в C+ + . Нужно знать этот порядок, и проблем не будет. В случае сомнения (и даже, если не сомневае­ тесь) используйте скобки.

Итерации в цикле do-while

Цикл do-while очень напоминает цикл while. Часто они взаимозаменяемы. Основная разница в том, что в цикле do-while условие проверяется в конце цикла, после каждой итерации, а в цикле while оно проверяется в начале цикла, перед итерацией.

Как и цикл while, цикл do-while управляет повторяющимся выполнением тела цикла, состоящего из одного оператора (или блока операторов в фигурных скоб­ ках). Цикл do-while имеет общую структуру:

предыдущий_оператор; do

оператор; // или {операторы } while (выражение);

следующий^оператор;

Глава 4 « Управление ходом выполнения программы С^+

125

После выполнения предыдущего_оператора обрабатывается тело цикла после ключевого слова do. Затем вычисляется выражение цикла. Если оно дает true, то тело цикла выполняется снова. Если при вычислении выражения получается false, то итерации прерываются и выполняется следующий_оператор.

Такая структура обеспечивает как минимум однократное выполнение тела цикла. Чтобы завершить цикл и предотвратить бесконечные итерации, в теле цикла должно изменяться выражение цикла.

Во избежание путаницы программисты часто заключают тело цикла в фигур­ ные скобки, даже если оно содержит лишь один оператор:

do

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

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

do

 

 

{ оператор;

 

 

} while (выражение);

/ /

фигурная скобка предупреждает о присутствии

 

/ /

точки с запятой

Построение тела цикла здесь аналогично циклу while:

инициализация_текущих_данных; do { изменение_текущих_данных; обработка_текущих_данных;

} while (вычисление_текущих_данных);

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

инициализация_текущих_данных:

установка total и count в О

изменение_текущих_данных:

ввод нового значения amount

обработка_текущих_данных:

если положительное, увеличить total и count

вычисление_текущих_данных:

сравнить amount с контрольным значением

 

Данная версия программы показана в листинге 4.15. Ее вывод будет соответ­

 

ствовать рис. 4.19.

 

Листинг 4.15. Реализация цикла do-while без предварительного чтения

#inclucle

<iostream>

 

using namespace std;

 

int main

()

 

{

 

 

double total, amount; int count;

// инициализация текущих данных

total = 0.0; count = 0;

do {

"Введите количество (для завершения

- О или отрицательное число): ";

cout «

cin »

amount;

// первый ввод текущих данных

126

Часть I ^ ВшеА^итв в програ1У1мирование на C^-i-

i f

(amount > 0)

{

total

+= amount;

 

count++;

} while

(amount > 0)

cout «

"\пСумма no " « count «

return

0;

/ /

проверка на конец данных

/ /

обработка текущих данных

/ / вычисление текущих данных транзакциям равна ' « t o t a l « endl;

Как можно видеть, с одной стороны цикл do-while упроидает инициализацию

и устраняет необходимость предварительного чтения (сравните с листингом 4.12),

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

Подсчет содержащихся во вводимой строке символов пробела можно делать в цикле do-while, как показано в листинге 4.16. Использование цикла do-while позволяет обойтись без предварительного чтения. Аналогично предыдуш^ему примеру из листинга 4.15, эта структура требует^проверки в теле цикла ввода контрольного значения. Следовательно, вычисление текуидих данных выполняется два>вды — в теле цикла и в логическом условии цикла.

Листинг 4.16, Цикл do-while для ввода символов

#include <iostream> using namespace std;

int main

()

 

 

 

 

 

{

 

 

 

 

 

 

 

 

 

char

ch;

int

count = 0, spaces = 0;

 

cout

«

 

"\пНаберите предложение и нажмите Enter\n"

do {

 

 

 

 

 

 

 

 

 

ch = cin . getO;

 

 

 

i f

(ch

!=

A n ' )

 

 

 

{

cout

«

ch;

 

 

 

 

i f

 

(ch

==

• ')

spaces++;

 

 

 

count++;

}

 

 

 

}

while

(ch

! =

' \ n ' ) ;

 

 

cout

«

 

"\пОбщее число символов

" « count «

endl;

cout

«

 

"Число пробелов равно "

« spaces «

endl;

return

0;

 

 

 

 

 

}

 

 

 

 

 

 

 

 

 

/ / инициализация данных

/ /

изменение текущих данных

/ /

проверка текущих данных

// обработка текущих данных

// вычисление текущих данных

Здесь значение символа ch устанавливается в присваивании и проверяется в операторах условия. Это открывает возможность комбинирования присваивания и проверки в одном операторе, как в листинге 4.17.

Листинг 4.17. Цикл do-while с присваиванием в операторе условия

#include <iostreafTi> using namespace std;

int main ()

{

char

ch; int count = 0, spaces = 0;

// инициализация данных

cout

« "\пНаберите предложение и нажмите Enter\n";

 

 

Глава 4 • Управление ходом выполнения программы C++

127

do {

 

// изменение текущих данных

if ((ch = cin.getO) != '\n' )

{ cout « ch;

// обработка текущих данных

if (ch == ' ') spaces++;

count++; }

// вычисление текущих данных

} while (ch ! = '\n');

cout «

"\пОбщее число символов " « count <<endl;

 

cout «

"Число пробелов равно " «

spaces <<endl;

 

return 0;

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

корректность, но программный кодстановится более лаконичным и элегантным.

Итерации с циклом for

Цикл for подходит в тех случаях, когда число итераций известно заранее, до начала цикла. Это не очень важный фактор. Визуально данная форма итерации представляется как совмещение трех наиболее значимых элементов архитектуры цикла: инициализация текущего значения перед первой итерацией, вычисление текущего значения перед началом следующей итерации и изменение текущего значения после итерации (перед началом следующей). В других циклах эти эле­ менты распределены по разным местам цикла.

Цикл for имеет следующую стандартную форму, где в скобках комбинируются три выражения, управляющие выполнением тела цикла (инициализация текущих данных, их вычисление и модификация). Эти выражения разделяются двоеточиями (что еще раз убеждает — изучение C++ никогда не превратится в скучное заня­ тия). Вот почему последнее выражение не имеет точки с запятой перед закрываю­ щей скобкой.

предыдущий_оператор;

for (начальное_выражение; продолж_выражение; инкр_выраж)

оператор; / / можно использовать составной оператор в фигурных скобках следующий_оператор;

Начальное_выражение вычисляется только один раз, перед первой итерацией. Здесь удобно инициализировать значения для работы цикла: индекс, счетчик

. элементов, сумму и пр.

Инкр_выраж вычисляется в конце следующей итерации, непосредственно после выполнения тела цикла. Это общепринятое место изменения текущих данных, приращения индексов, счетчиков, меток и т. д.

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

Нужно понимать, что цикл for эквивалентен следующему циклу while:

предыдущий_оператор; начальное_выражение; while (продолж_выражение)

{ оператор;

/ / или последовательность операторов

инкр_выраж;

}

следующий_оператор;

I 128 I

Часть i ^ Введение в прс

В листинге 4.18 показан пример обработки транзакций с использи1зсши^:м цик­ ла for. Инициализация включает в себя установку значения count в О, а проверка на продолжение предусматривает проверку контрольного значения (вот почему предварительное чтение все же необходимо). Инкремент — это увеличение пере­ менной count.

Листинг 4.18. Реализация обработки транзакций с использованием цикла for

#inclucle

<iostream>

 

using namespace std;

 

int main

()

 

 

{

 

 

 

double total, amount; int count;

// разная инициализация

total = 0.0;

cout «

"Введите количество (для завершения

- О или отрицательное число): ";

cin »

amount;

// ввод текущих данных

for (count=0; amount>0; count++)

// три выражения

{ total += amount;

// обработка текущих данных

cout «

"Введите количество (для завершения - О или отрицательное число): ";

cin » amount; }

// изменение текущих данных

cout «

"\пСумма по " « count << " транзакциям равна " <<total « endl;

return 0;

 

 

}

 

 

 

 

 

Каждая из трех составляющих в цикле for представляет собой выражение. Это

 

 

глубокомысленное наблюдение означает, что в каждом таком выражении может

 

 

использоваться последовательность разделенных запятыми выражений. Не забы­

 

 

вайте, что запятая — полноправная операция C++. Ее операнды (выражения)

 

 

вычисляются слева направо, и возвращается самое правое значение. В цикле for

 

 

возвращаемые значения не важны — они отбрасываются. Единственное исключе­

 

 

ние — продолж_выражение, которое определяет, нужна ли следующая итерация.

 

 

Это означает, что начальное_выражение можно расширить, как показано в листин­

 

 

ге 4.19.

 

Листинг 4.19. Цикл for с операцией ''запятая" в начальных выражениях

#inclucle <iostreafn> using namespace std;

 

int main

()

 

 

{

 

 

// нет инициализации

double total, amount; int count;

cout «

"Введите количество (для завершения

- О или отрицательное число): ";

cin »

amount;

// ввод текущих данных

for (total = 0.0; count=0; amount>0; count++)

{ total +=amount;

 

cout «

"Введите количество (для завершения - О или отрицательное число): ";

cin »

amount; }

 

cout << "\пСумма по " « count « "транзакциям равна " «total « endl; return 0;

Е щ е более интересна программа с вводом иобработкой символов, показанная

в листинге 4.20. Здесь в начальном_выражении используются выражения, разделен­ ные запятыми, априсваивание используется как часть сравнения в продолж_выражении (сравните эту версию слистингами 4.13 и 4.16).

Глава 4 • Управление х о д о м выполнения програ1^1\ль1 С-^-^

\ 129 1

Листинг 4.20. Цикл for с присваиванием в продолж_выражении

#inclucle

<iostream>

 

 

using namespace std;

 

 

int main

()

 

 

 

{

 

 

 

 

 

char ch; int count, spaces;

 

/ / нет инициализации

cout

«

"\пНаберите предложение и нажмите Enter\n";

for

(count=0,

spaces=0; (ch=cin.get())! = ' \ n ' ; count++)

{ cout « c h ;

 

 

/ / обработка следующего вводимого символа

i f

(ch == '

' ) spaces++; }

 

 

cout

«

"\пОбщее число символов "

« count «

endl;

cout

«

"Число пробелов равно " «

spaces «

endl;

return

0;

 

 

 

}

 

 

 

 

 

 

 

Еш,е один

интересный

момент — возможность определения

переменных

 

в начальном_выражении цикла for. Данная программа складывает квадраты первых

 

натуральных чисел. Цикл for инициализирует переменную п значением 1, прове­

 

 

 

 

ряет, достигает ли она предела num и увеличивает п

Введите, сколько нужно сложить квадратов: 4

после каждой итерации. Так как переменная

п ис­

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

Сумма квадратов равна 30

 

 

 

 

 

 

необходимости задавать для нее более широкую об­

Рис. 4 . 21 . Результат

выполнения

ласть действия. Вот почему она определяется в опе-

раторе for, а не в функции main(). Это популярный

программы

из листинга 4.21

принцип С4- + . Результат тестового выполнения про-

(сложение натггуральных чисел)

 

. о i

 

 

^

 

^^

^

 

граммы показан на рис. 4.21.

 

 

Листинг 4.21. Вычисление суммы квадратов с помощью цикла for

 

 

#inGlude

<iostream>

 

 

 

 

 

 

using namespace std;

 

 

 

 

 

 

int main

()

 

 

 

 

 

 

{

 

 

 

 

 

 

 

int sum=0, num;

 

 

 

 

 

 

cout "\пВведите, сколько нужно сложить квадратов: ";

 

 

cin »

num;

 

 

 

 

 

 

for (int n = 1; n <= num; n++)

 

 

 

 

{ sum += n * n; }

 

 

endl;

 

 

cout «

"Сумма квадратов равна " « sum «

 

 

return 0;

 

 

 

 

 

 

}

 

 

 

 

 

 

 

 

Как уже было показано в листингах 4.19 и 4.20, C + + позволяет программисту

 

инициализировать несколько переменных в начальном_выражении

цикла

for.

 

Кроме того,

C + + дает

возможность определять в начальном выражении

 

несколько переменных, если все они одного типа. В листинге 4.22 переменные п

 

и sum определяются в цикле. К тому же, переменная sum обновляется в про-

 

долж_выражении — в качестве инструмента используется операция-запятая. Резу­

 

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

 

Как видно, тело цикла вырождается в пустой оператор.

 

 

Соседние файлы в предмете Программирование на C++