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

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

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

130

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

Листинг 4.22. Цикл for, генерирующий пустой оператор

#include <iostream> using namespace std;

int main

()

 

 

{

 

 

 

int num;

 

 

cout »

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

 

cin »

num;

n++);

// ! !

for (int sum = 0, n = 1; n <=num; sum+=n*n;

cout «

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

endl;

 

return 0;

 

 

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

for (int

sum = 0, n = 1; n <= num; sum+=n*n, n++)

;

/ / !!

Другие программисты вовсе избегают пустых операторов, поскольку они вносят путаницу, а применяют вместо них структуру, аналогичную показанной в листин­ ге 4.21, где в теле цикла содержится хотя бы один оператор. Самая большая проблема программы из листинга 4.21 — ее переносимость. Переменная sum определяется в цикле, но используется после его завершения. "Оригинал" С+ + допускает это, но новый стандарт С+Н- интерпретирует такие действия, как синтаксическую ошибку: в цикле можно определять только переменные, исполь­ зуемые в самом цикле, но не вне его. Большинство компиляторов такой код компилируют,* но применять данный метод не следует: обычно не стоит увлекаться оптимизацией циклов for.

Операторы перехода в C+ +

Условные операторы и операторы цикла — неотъемлемый инструмент про­ граммирования. Без них нельзя написать даже простейшую программу. Они — важнейшая необходимость. Другие операторы управления полезны, но не столь необходимы. Они представляют синтаксические дополнения, делающие программу толково написанной и более эстетически привлекательной.

Такими операторами C++ являются различные виды переходов. Разработчики программ любят переходы, поскольку они позволяют им результативно и эффек­ тивно передавать управление в любое место исходного кода программы. Между тем, программу с переходами труднее анализировать, чем программу без оных. Чтобы понять результат выполнения программы с последовательными оператора­ ми, сопровождающему ее программисту нужно разобраться только в тех операто­ рах, которые непосредственно предшествуют анализируемому. Когда управление передается на этот оператор из других мест программы, на работу оператора влия­ ют все такие участки кода. Анализ программы усложняется. Вот почему у перехо­ дов плохая репутация.

В C++ делается попытка предложить компромиссный вариант. Он допускает переходы, чтобы программисты могли писать более мощный и лаконично состав­ ленный исходный код. Но переходы здесь ограничены, чтобы при сопровождении программы не пришлось решать слишком сложные задачи.

Глава 4 » Управление ходом выполнения программы С-ь+ Ci3i3

Оператор break

Этот оператор используется для немедленного выхода из цикла. После выпол­ нения данного оператора управление передается на оператор, следующий за цик­ лом. Выход из цикла в середине его выполнения — шаг, конечно, решительный, но он не слишком осложняет управляющую структуру. Оператор break нельзя использовать для выхода из ветви оператора if (в противном случае управляющая структуру стала бы чрезмерно запутанной). Позднее мы рассмотрим применение оператора break внутри операторов switch.

Нет никакого смысла выполнять оператор break безусловно. Это означает, что цикл не работает вовсе. Обычно break выполняется в операторе условия. В логи­ ческом выражении этого условия задается условие прекращения цикла. Часто такой метод позволяет упростить условие цикла. Например, можно просто по­ строить "бесконечный" цикл с выходом по break.

Рассмотрим листинг 4.12 с циклом, обрабатывающим вводимые данные до получения контрольного значения. В условии цикла используется значение пере­ менной amount. Следовательно, данная переменная должна инициализироваться перед циклом, а это задача предварительного чтения.

cout

«

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

cin

»

amount;

/ /

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

while (amount > 0)

/ /

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

{ t o t a l

+= amount;

/ /

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

count++;

 

 

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

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

cin »

amount;}

/ /

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

Использование оператора break позволяет заменить условие цикла нэ нечто неизменяемое, например на while (1 == 1). Так как это условие всегда равно true, при записи данного выражения гораздо меньше шансов сделать ошибку. Посколь­ ку в условии не нужно применять значение amount, нет нужды в предварительном чтении. Значение amount можно получать в начале цикла, а не в конце. Проблема этой структуры цикла — прекращение цикла при получении контрольного значе­ ния. Решение дает оператор break. Итерации нужно продолжать, пока amount > 0. Следовательно, условием прекращения цикла является отрицание этого, т. е. amount <= 0.0. Когда это (отрицательное) условие содержит true, выполняется оператор break и управление передается из цикла на следующий оператор:

while (1 == 1)

/ /

бесконечный цикл

{ cout «

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

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

cin

»

amount;

/ /

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

i f

(amount <= 0.0) break;

/ /

явный выход

t o t a l

+= amount;

/ /

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

count++; }

 

 

Можно возразить, что перенос проверки amount из выражения цикла на опера­ тор break не особенно влияет на сложность программы. Но зато позволяет устра­ нить предварительное чтение.

В версии данного алгоритма с циклом do-while (см. листинг 4.15) не использу­ ется предварительное чтение, но дважды проверяется, содержит ли следующее вводимое число допустимое значение (в середине и в конце цикла):

do {

 

 

 

 

cout «

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

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

cin »

amount;

/ /

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

i f

(amount > 0)

/ /

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

{

t o t a l += amount;

/ /

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

I

132 I

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

 

 

count++;

 

 

 

 

} while (amount > 0)-;

 

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

 

 

Применение оператора break позволило заменить условие цикла на тривиальное

 

 

условие, которое всегда равно true (типа 1 == 1 или даже просто 1). Для завер­

 

 

шения цикла при появлении контрольного значения условие amount > О нужно

 

 

отрицать, аналогично предыдущему примеру. Когда amount <= О, оператор break

 

 

передает

управление на

следуюндий за циклом оператор. Структура цикла

 

 

в чем-то упрондается — нет необходимости в локальном составном операторе

 

 

с его фигурными скобками. Обратите внимание, что while (1) — вполне закон­

 

 

ная альтернатива while (1 == 1), так как в С4--Ь ненулевое значение всегда равно

 

 

true:

 

 

 

 

 

 

do {

 

 

 

 

 

 

cout «

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

 

 

cin

»

amount;

/ /

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

 

 

i f

(amount <= 0) break;

/ /

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

t o t a l

+= amount;

'

/ /

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

count++;

 

/ /

не нужен составной оператор

} while

(1)

 

/ / н е требуется вычисление здесь текущих данных

Вот еще один пример использования оператора break в проверяемом диапазоне, часто применяемого для контроля допустимости ввода. Предположим, что поль­ зователю нужно ввести ответ в диапазоне от 1 до 5. Если пользователь делает ошибку, ввод должен повторяться, пока не будет введено допустимое значение. В листинге 4.23 используется цикл do-while, так как тело цикла должно выпол­ няться хотя бы один раз. Переменная error_flag устанавливается в 1, если вводимое значение недопустимо, и в О, если оно попадает в диапазон.

Листинг 4.23. Использование цикла do-while для проверки допустимости ввода

#include

<iostream>

 

 

using

namespace std;

 

 

const

int

N = 5;

 

 

int main

()

 

 

{

 

 

 

 

int num, error_flag;

 

do {

 

 

 

cout

« "Введите число между 1 и " << N << ": ";

cin

>> num;

 

 

i f

(num < 1 11 num > N)

 

{

cout « "Ввод некорректен, повторите\п";

 

 

error_flag

= 1;

}

else

 

 

 

 

 

error_flag

= 0;

 

 

}

while (error_flag ==1);

cout

«

"Вы ввели " «

num « endl;

return

0;

 

 

}

 

 

 

 

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

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

П Щ

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

. ние ^- передавать информацию из одной части программы в другую. Это увеличи­ вает связность программного кода и его сложность. Другим способом реализации данного алгоритма является повторение теста в условии цикла (вместо использо­ вания флага ошибки):

do {

 

 

 

cout «

"Введите число между 1 и " « N « " : ";

Gin »

num;

i f

(num < 1 I I num > N)

 

cout

«

"Ввод некорректен, повторите\п";

}

while

(num < 1 11 num > N);

Это более разумное решение. Еш.е один подход состоит в применении бесконеч­ ного цикла и прерывании его выполнения, когда значение допустимое. Следова­ тельно, цикл продолжается с запросом данных, когда п < 1 или num > N, и завер­ шается, когда это условие принимает значение false.

do {

 

 

 

 

cout

«

"Введите число между 1 и " « N « " : ";

cin

»

num;

i f

(!(num

< 1 I I num > N)

 

cout

«

"Ввод некорректен, повторите\п";

}

while

(true);

Отметим, что это третья форма "бесконечного" цикла, где литеральное значение (true) используется в качестве условия его продолжения.

Многие программисты предпочитают явное отрицание условия составного оператора. Для этого можно заменить каждую операцию && на операцию | |, а каждую операцию | | на && и применять отрицание отдельных условий. Рассмот­ рим, например, выражение a1 && (~а2) | | аЗ, где a1, а2 и аЗ — булевы выраже­ ния. Его отрицанием будет (~a1) | | а2 && (~аЗ). В нашем случае отрицание для прерывания цикла выглядит так:

do {

 

 

 

 

 

cout

«

"Введите число между 1 и " « N « " :

";

cin

»

num;

 

i f

(num >=1 && num <= N) break;

/ / просто и красиво

 

cout

«

"Ввод некорректен, повторите\п";

 

}

while

(true);

 

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

Оператор break — один из достаточно простых и эффективных переходов в C+ + . Другие переходы либо более опасны, либо не так эффективны.

Оператор continue

Оператор continue — еш,е более простая модификация оператора break. Как и break, он используется в конструкциях циклов и пропускает остальную часть тела цикла, заключенную между оператором continue и его концом.

Оператор continue можно использовать в циклах while, do-while и for. В циклах while и do-while он переходит к концу или началу цикла для проверки условия цикла. В цикле for оператор continue не обходит выражение инкремен­ та, а только пропускает остальную часть тела цикла.

с 134 J

Часть I * Введение в программирование но С-^+

 

Рассмотрим, например, листинг 4.11 (без предварительного чтения) и его

 

модификацию, которая решает проблемы за счет обновления текуш,их данных,

 

когда контрольное значение еще не введено.

 

 

while (amount > 0)

 

/ /

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

 

{ cout «

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

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

 

cin

»

amount;

 

/ /

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

 

i f

(amount > 0)

continue

/ /

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

 

 

{

t o t a l += amount;

/ /

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

 

 

 

count++;

} }

 

 

 

Вместо использования блока в операторе условия можно отрицать условие

 

и применить оператор continue:

 

 

 

while (amount > 0)

 

/ /

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

 

{ cout «

"Введите

количество

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

- О или отриц.число); ";

 

cin

»

amount;

 

/ /

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

 

i f

(amount <= 0)

continue

/ /

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

 

t o t a l += amount;

 

/ /

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

 

count++; }

 

 

 

Улучшение не очень значимое. Как уже отмечалось, оператор continue весьма примитивен. Его всегда можно заменить условным оператором. Нечасто прихо­ дится видеть оператор continue, значительно улучшаюш,ий исходный код. На са­ мом деле такой пример встретился мне лишь однажды, и я даже подумал, что его стоит записать, но что-то отвлекло меня, и теперь я не могу привести этот пример.

Оператор goto

Оператор goto — король переходов. Именно неограниченное применение этих операторов вызывало столько дискуссий: шли споры вокруг того, вредны ли такие переходы и следует ли объявить их вне закона. Действительно, во многих совре­ менных языках программирования запреш,ены неограниченные переходы. И в C-f--h тоже.

C+ + допускает переходы goto только в пределах одной функции. Это означает, что и оператор goto, и целевой оператор (куда выполняется переход) обязаны на­ ходиться в одной функции. Кроме того, не допускаются переходы через определе­ ния. Достаточно ограничительная мера для обычного перехода. Вот почему в C+ + оператор goto менее вреден, чем в других языках. Вот как он здесь выглядит:

void foo

 

 

{ ...

 

 

goto labell;

/ /

нет двоеточия после имени метки

int х;

/ /

переход через определение: - синтаксическая ошибка

l a b e l l : оператор;

/ /

двоеточие после имени метки

goto labell; }

/ /

нет перехода через определение: ОК

Метка — это идентификатор. Она помеш^ается перед оператором, куда пере­ дается управление, и в конце оператора goto. Имена меткам придумывает про­ граммист. В отличие от идентификаторов переменных, функций и типов, метки определять не нужно. Они просто используются. Идентификаторы меток имеют свое собственное пространство имен. Это означает, что их имена не конфликтуют с другими идентификаторами: именами переменных, функций или типов.

За меткой, применяемой в качестве цели перехода, ставится двоеточие. В метке, которая указывается в операторе goto, двоеточие не требуется — опера­ тор заканчивается точкой с запятой.

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

135

В листинге 4.24 приведен пример обработки транзакций, реализованный без циклов — только с операторами условия и переходами. Здорово, не правда ли?

Листинг 4.24. Обработка транзакций с помощью переходов goto

#inclucle <iostream> using namespace std;

int main

()

 

{

 

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

double total=0.0, amount; int count=0;

start:

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

cout «

cin »

amount;

// ввод (изменение) текущих данных

if (amount <=0) goto finish;

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

total += amount;

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

count++;

// переход к началу цикла

goto start;

finish:

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

endl;

cout «

return 0;

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

Переходы return и exit

Оператор return представляет переход, который завершает выполнение функ­ ции. Если это функция mainO, то программа завершается. Если это некая другая функция, вызываемая из main() прямо или косвенно, то данная вызываемая функ­ ция завершает работу и управление возвращается вызвавшей ее функции.

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

Оператор return может иметь или не иметь аргументы. Если функция опреде­ лена как void, то в return не должно быть аргументов. C++ унаследовал из С две формы функции main(): одну с возвращаемым типом int, другую — с типом void. В новом стандарте C++ предпочтение отдается первой форме, однако можно встретить немало унаследованного кода C++, в котором функция main() не имеет возвращаемого типа, а следовательно, return в ней не используется. Если в функцию void main() включить необязательный оператор return, то он может выглядеть так:

void main(void)

 

{ . . .

 

return; } .

/ / нет аргумента, нет круглых скобок

Когда оператор return используется в функции void, он не должен иметь ни аргумента, ни скобок: return О будет ошибкой, returnO тоже.

В предыдущих примерах использовалась функция main(), возвращающая целочисленное значение. Как и любая отличная от void функция, функция main() должна иметь оператор return и он должен возвращать целочисленное значение

 

136

I

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

 

 

 

(или значение, которое можно преобразовать в целое). Функция main() выглядит

 

 

 

так:

 

 

 

 

 

 

i nt

main(voicl)

 

 

 

 

 

 

{ . . .

 

 

 

 

 

 

return 0; }

 

/ /

аргумент обязателен, а круглые скобки - нет

 

 

 

 

Компиляторы

C + +

должны старательно воспринимать следующую форму

 

 

 

функции main():

 

 

 

 

 

 

main(void)

 

/ /

по умолчанию возвращается тип int

 

 

 

{ . . .

 

 

 

 

 

 

return 0; }

 

/ /

круглые скобки - необязательны

 

 

 

 

Как уже упоминалось, в C + + пропуск информации о возвращаемом типе не

 

 

 

означает, что тип возвращаемого значения (void). Это означает тип int, что

 

 

 

соответствует унаследованной из С философии, согласно которой лаконично со­

 

 

 

ставленная программа лучше, чем программа не столь эффектная. Следовательно,

 

 

 

нужно помочь программисту писать эффектные программы (опуская возвращае­

 

 

 

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

 

 

 

 

Позднее эта философия была вытеснена мнением, что такие программы за­

 

 

 

ставляют сопровождающего ПО программиста тратить больше времени и усилий

 

 

 

на ее понимание, т. е. программа кажется ему более сложной. Программист,

 

 

 

желающий писать эффектные программы, должен подумать в первую очередь

 

 

 

о читабельности и понятности исходного кода, в частности для тех, кто не имеет

 

 

 

достаточного опыта и уровня подготовки.

 

 

 

Оператор return делает возвращаемое значение доступным для вызывающей

 

 

 

функции. Например, вызов функции cin.getO, использованной в предылущих

 

 

 

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

 

 

 

Это означает, что в функции get() есть некий оператор вида return с;, где с —

 

 

 

имя переменной (оно может быть и другим) типа char.

 

 

 

Когда функция main() возвращает значение, его воспринимает операционная

 

 

 

система и оно позволяет судить о нормальном или ненормальном завершении

 

 

 

программы. На многих платформах возвращаемое программой значение отбрасы­

 

 

 

вается.

 

 

 

 

 

 

Это не означает, что можно опустить оператор return, если разрабатываемая

 

 

 

функция (включая функцию main()) возвращает типизированное значение. Вы

 

 

 

взяли на себя обязательство (отличный от void возвращаемый тип), и с этим

 

 

 

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

 

 

 

void, то функция должна иметь оператор return, возвращающий значение (выра­

 

 

 

жение) соответствующего типа. Скобки вокруг выражения в return не обязатель­

 

 

 

ны (но используются).

 

 

 

 

 

На количество операторов return никаких ограничений нет. Если return вы­

 

 

 

полняется в середине функции, то остальная часть функции просто игнорируется.

Введите

операнд,

операцию

и другой операнд: 22/0

 

Рассмотрим упрощенный пример калькуля­

 

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

Деление наноль

 

 

 

 

операнда и операцию, а затем выводит результат

 

 

 

 

 

 

 

операции (листинг 4.25). Для демонстрации здесь

PJ

^ по

 

выполнения

 

 

используется функция main(), не возвращающая

гИС.

4.ZZ. Результат

4.25

 

г,

 

 

программы

из листинга

 

значения. Результат выполнения программы пред-

 

 

(деление на ноль)

 

 

ставлен на рис. 4.22.

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

| 137 |

Листинг 4.25. Упрощенный калькулятор

#inclucle <iostream> using namespace std;

void main(void)

{

double opi, op2; char ch;

cout «

"Введите операнд, операцию и другой операнд: ";

cin »

ор1 » ch » ор2;

 

 

if (ch =- '*')

 

ор1 + ор2 « endl;

cout « "Результат равен " «

else

 

'*')

 

 

 

if (ch ==

 

op1 * op2 « endl;

cout «

"Результат равен " «

else

 

 

 

 

 

if (ch =='-')

 

 

 

 

cout « "Результат равен " « op1 - op2 « endl;

else

 

 

 

 

 

if (ch == 7')

 

 

 

if (op2 !

= 0.0)

 

op1 / op2 « endl;

 

 

cout «

"Результат равен " «

 

else

"Делениена ноль" «

endl;

 

else

cout «

 

 

 

 

 

 

cout « "Недопустимая операция" « endl;

}

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

Во-первых, стоит обсудить форматирование. Код программы представляет собой условный оператор с глубоким уровнем вложенности. Для каждого уровня вложенности задается отступ на пару пробелов вправо. Форматирование доста­ точно хорошо показывает, из чего состоит код (вложенные условные операторы), однако он не подчеркивает (для сопровождаюи;его программиста) выполняемые действия.

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

Ниже приведена другая версия, в которой условные операторы отражают логику обработки:

i f

(ch

== ' + ' )

 

 

/ /

первый

случай

cout

«

"Результат равен "

«

ор1 + ор2 «

endl;

 

else i f

 

(ch == ' * ' )

 

 

/ /

второй

случай

cout

«

"Результат

равен "

«

ор1 * ор2 «

endl;

 

else i f

 

(ch == ' - ' )

 

 

/ /

третий

случай

cout

«

"Результат

равен "

«

ор1 - ор2 «

endl;

 

else i f

 

(ch == ' / ' )

 

 

/ /

четвертый случай; более сложный

{

i f

(ор2

!= 0.0)

 

 

 

 

 

 

cout

«

"Результат равен "

« ор1 / ор2 « endl;

 

 

else

 

 

 

 

 

 

 

 

cout

«

"Деление на ноль" «

endl;}

 

 

I

138 I

Часть I • Введение в програтттроваишв ыа C++

 

 

 

 

else

 

 

 

 

 

 

 

 

 

 

 

 

cout

«

"Недопустимая операция"

« endl;

 

 

 

 

 

 

Операторы return могут превратить отдельные ветви обработки в независи­

 

 

мые условные операторы, следуюш,ие один за другим без ключевых слов else:

 

 

i f

(oh == ' + ' )

 

 

 

/ /

первый случай

 

 

 

{

cout

«

"Результат

равен "

«

ор1 + ор2 «

endl;

return;

}

 

 

i f

(ch == ' * ' )

 

 

 

/ /

второй

случай

 

 

 

{

cout

«

"Результат

равен "

«

ор1 * ор2 «

endl;

return;

}

 

 

i f

(ch

= = ' - ' )

 

 

 

/ /

третий

случай

 

 

 

{

cout

«

"Результат

равен "

«

ор1 -

ор2 «

endl;

return;

}

 

 

i f

(ch == V ' )

 

 

 

/ /

четвертый случай: более сложный

 

 

{

i f

(ор2

!= 0.0)

 

 

 

 

 

 

 

 

 

 

cout

«

"Результат

равен "

«

ор1 /

ор2 «

endl;

 

 

 

 

 

else

 

 

 

 

 

 

 

 

 

 

 

 

cout

«

"Деление на ноль"

<< endl;

 

 

 

 

 

 

 

return;}

 

 

 

 

 

 

 

 

 

 

cout «

"Недопустимая операция" «

endl;

 

 

 

Еще один популярный метод завершения — вызов функции exit(), входяш^ей в стандартную библиотеку stdlib.h. Хотя функцию завершает только оператор return (если это функция main(), то он завершает и программу), вызов exit() позволяет завершить программу вне зависимости от того, какая функция сделала этот вызов. Функция exit О вызывается с одним целочисленным аргументом. Согласно популярному соглашению, О означает нормальное завершение, а 1 — ненормальное. С помош,ью этих значений программа передает ОС информацию о способе завершения.

Чтобы заш,итить программу, желаюшую таким способом обш,аться с ОС, от будуш,их изменений в соглашениях, в файле stdlib.h (или, согласно новому стандарту, cstdlib) определяются две символические литеральные константы: EXIT_SUCCESS и EXIT_FAILURE. Их рекомендуется использовать вместо кодов возврата О и 1. Вот пример применения этих констант в приведенной выше программе:

Листинг 4.26. Вызовы библиотечной функции exit()

#include <iostream> #include <cstdlib> using namespace std;

void main(void)

{

double op1, op2; char ch;

 

 

 

cout «

"Введите операнд, операцию и другой операнд: ";

cin »

ор1 »

ch » ор2;

 

 

// первый случай

if (ch=='+')

ор1 + ор2 «

cout «

"Результат равен " «

endl;

else if (ch=='*')

ор1 * ор2 «

// второй случай

cout «

"Результат равен " «

endl;

else if (ch ==*-')

ор1 - ор2 «

// третий случай

cout «

"Результат равен " «

endl;

else if (ch == '/')

 

 

// четвертый случай: более сложный

{ if (ор2 != 0.0)

 

ор1 / ор2 « endl;

 

cout «

"Результат равен " «

else

 

"Деление на ноль" «

endl;}

 

 

cout «

 

Глава 4 • Управление х о д о м выполнения nporpai^r^bi C-t-Hh

| 139

|

else

/ /

пятый случай: ошибка

 

 

{ cout « "Недопустимая операция" «

endl;

 

 

 

exit(EXIT_FAILURE); }

//провал

 

 

exit(EXIT^SUCCESS);

/ /

все OK

 

 

}

На самом деле эти библиотечные константы имеют значения О и 1. Идея в том, что в один прекрасный день по каким-то причинам в операционной системе может быть введен другой набор значений, ожидаемых от программы С+4-. Тогда литералы О и 1 приведут к проблемам — ОС их не поймет. В то же время зна­ чения библиотечных констант EXIT_SUCCESS и EXIT_FAILURE легко исправить, и программа, использующая данные имена, снова будет общаться с операционной системой корректно. Вынужденная логика, но многие программисты применяют эти константы.

Оператор switch

Оператор switch — это инструмент для принятия в программе многозначных решений, позволяющих выполнять одну из многих ветвей. Альтернативные пути выбираются в зависимости от значения целочисленного выражения — выраже­ ния в круглых скобках за ключевым словом switch. Остальная часть оператора состоит из ветвей, заключаемых в фигурные скобки (открывающая и закрываю­ щая фигурные скобки обязательны).

Каждая ветвь состоит из ключевого слова case, значения того же типа, что и выражение switch, двоеточия и набора из одного или более операторов, завер­ шающихся точкой с запятой:

switch (выражение) {

/ /

фигурные скобки обязательны

case конст_выраж1: операторы;

/ /

первая

ветвь

case конст_выраж2: операторы;

/ /

другие

ветви

default: операторы;

/ /

ветвь по умолчанию

}

 

 

 

Выражение в операторе switch может быть только типа char, short, int или long (целые типы). Типы с плавающей точкой (float, double или long double) не допускаются. Нельзя использовать и типы, определяемые программистом: структуры, массивы или классы.

Метки в case должны быть выражениями-константами, т. е. константами этапа компиляции, и того же типа, что и выражение switch.

Например, упрощенный калькулятор из листинга 4.25 можно реализовать с помощью оператора switch:

Листинг 4.27. Калькулятор с оператором switch (плохая программа)

#include <iostream> #include <cstdlib> using namespace std;

void main(void)

{

double op1, op2; char ch;

cout « "Введите операнд, операцию и другой операнд: "; cin » ор1 » ch » ор2;

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