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

Давыдов В.Г. - Программирование и основы алгоритмизации - 2003

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

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

4.7. Оператор switch

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

char

 

 

 

ch;

 

 

switch

(

ch )

 

 

 

 

{

 

'a':

 

 

 

 

case

=

1;

break;

 

case

1ndex

 

'Ь':

=

2;

break/

 

 

 

index

 

case

'у':

 

 

break;

 

case

Index

=

25;

 

'z ':

=^ 26;

break;

 

 

 

index

 

default:

 

 

 

 

}

 

index

=

0;

 

 

 

 

 

 

 

 

Синтаксис

оператора switch

(переключатель) поясняется диа­

граммой, приведенной на рис. 33.

 

Выполнение оператора switch

начинается с вычисления заклю­

ченного в скобки

"выражения", которое долэюно давать результат

целого

или символьного

типа. Затем просматриваются друг за дру­

гом префиксы case (случай), вычисляются указанные после служеб­ ного слова case "константныевыражения" и полученные значения сравниваются со значением выражения, указанного после служебно­ го слова switch. Если эти результаты совпали, то управление переда­ ется оператору, следующему за соответствующим служебным сло­ вом case. Если ни одного совпадения не произошло и при этом ука­ зано необязательное служебное слово default (по умолчанию), то

100

управление передается оператору, следующему за default. Если ни одного совпадения не произошло, а служебное слово default отсут­ ствует, то управление передается оператору, непосредственно сле­ дующему за последней фигурной скобкой оператора switch.

OnepaTop_switch

 

 

 

 

 

 

 

 

 

( switch V ^ T

(

V H Выражение

V->(

)

V w

OnepaTop_case

Оператор case

 

 

 

 

 

 

 

 

 

case

'N

\

I Константное

I

I

^ / ' ^ T ^

[

Оператор V-ffi }

 

J

_выражение

|

V

' У

I fI

 

Ц^ default y

Рис. 33. Синтаксическая диаграмма переключателя

После передачи управления в блок операторов case исполне­ ние указанных в нем операторов производится до конца блока (от одной альтернативы к другой), если только последовательность вы­ полнения операторов не будет изменена операторами break или goto. Действие оператора break сводится к передаче управления оператору, следующему за последней закрывающей фигурной скоб­ кой switch (рис. 34). Следует также отметить, что порядок следова­ ния case в блоке безразличен.

Подведем итоги всему сказанному. Для программирования ветвлений на три или более направлений имеются две альтернативы - использование вложенных операторов //или использование опера­ тора switch. Из приведенных примеров видно, что использование оператора switch является более наглядным и простым. Однако этим оператором нельзя воспользоваться, если проверяемое выражение имеет вещественный тип или если проверяется комбинация не­ скольких условий. В этом случае приходится использовать вложен­ ные операторы if

4,8. Оператор while

Этот оператор уже рассматривался нами. Он является операто­ ром цикла с предусловием (рис. 35):

101

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

{

case конст._выр,_1: Операторы break; —

case конст._выр,_2: Операторы break;

//Выражение не может быть

//вещественного типа

Рис. 34. Переключатель

Оператор while

 

(^ while ")-КГО~Л Выражение

Оператор

Рис. 35. Синтаксическая диаграмма оператора while

Работа оператора while заключается в следующем.

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

2.Если значение "выражения" отлично от нуля ("истина"), то выполняется "оператор" и осуществляется переход к п. 1.

3.Если значение "выражения" равно нулю ("ложь"), то выпол­ нение цикла завершается и управление передается оператору, сле­ дующему за оператором while.

Таким образом, оператор while эквивалентен следующей по­ следовательности операторов:

cycle:

±f( выражение )

 

 

 

 

 

 

{

 

 

 

 

 

 

 

опера

тор

 

управление

на

оператор^

 

 

// Оператор передает

об

 

//

следующий

за меткой cycle

(см.

подробнее

 

//

операторе

goto

ниже)

 

 

 

 

goto

cycle;

 

 

 

 

 

}

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

102

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

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

/ / пример

1

== 1

) ;

//

В качестве

тела цикла

использован

while ( fun(

)

 

 

 

 

//

пустой

оператор

 

В этом примере вся работа осуществляется за счет выполнения

условия цикла

и не

требуется

никаких

других операторов (fun() -

функция, возвращающая некоторое целое значение; как только она вернет значение, отличающееся от единицы - выполнение цикла за­ кончится). В подобных случаях щ\л удовлетворения синтаксических правил следует в качестве тела цикла указать точку с запятой, кото­ рая обозначает пустой оператор.

/ / пример

2

while ( 1

)

{

 

bxrea-k

;

}

 

Этот пример демонстрирует преднамеренное создание "беско­ нечного" цикла. Так как "выражение" в этом цикле всегда имеет значение 1 ("истина"), то цикл может исполняться неограниченное число раз. Одним из способов завершения выполнения такого цикла является использование в его теле оператора break. Как только это произойдет, управление будет передано оператору программы, сле­ дующему за оператором while. Оператор break подобным же обра­ зом действует в теле цикла и других циклических операторов, кото­ рые будут рассмотрены ниже.

Циклические операторы, так же как и условные операторы,

можно вкладывать друг в друга. В подобных

случаях

оператор

break

обеспечивает

выход только

из того цикла,

в теле

которого

он на­

ходится.

 

оператор continue^ который позволяет

В языке

предусмотрен

пропускать оставшуюся после него часть тела цикла и начать новую итерацию, т.е. новое выполнение тела цикла сначала. Таким обра­ зом, по своему действию операторы break и continue являются опе­ раторами с ограниченным диапазоном передачи управления. Дейст­ вие их показано на рис. 36.

103

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

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

{

{

break;

continue;

}

}

Рис. 36. Использование операторов break и continue в цикле while

4.9. Оператор do-while

Оператор do-while, часто называемый оператор do, является циклом с постусловием и имеет синтаксическую диаграмму, пред­ ставленную на рис. 37 (обратите внимание на наличие в конце опе­ ратора точки с запятой).

Оператор do-while

- ^ / ddo j - H Оператор V-U while V ^ / ( V H Выражение Н->Г ) \>( \ )—•

Рис. 37. Синтаксическая диаграмма оператора do-while

Работа оператора поясняется следующей эквивалентной по­ следовательностью операторов:

cycle:

оператор

±£( выражение ) goto cycle;

Из эквивалентного представления следует, в частности, что в отличие от цикла while, тело цикла do-while, независимо от значения "выражения", будет выполнено не менее одного раза. Для изменения хода выполнения операторов, составляющих тело цикла можно вос­ пользоваться операторами break и continue (рис. 38).

do

do

{

{

Ьгяак"

continue*

}

}

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

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

Рис. 38. Операторы break и continue в цикле do-while

104

Остальные особенности цикла while (использование пустого оператора, "бесконечный" цикл, вложенность циклов и т.п.) в рав­ ной степени относятся и к циклу do-while.

4.10Оператор for

Этот оператор также является циклом с предусловием и имеет синтаксическую диаграмму, представленную на рис. 39. Работа опе­ ратора for поясняется следующей эквивалентной последовательно­ стью операторов:

выражение!

cycle:

if( выражение2 )

{

опера тор выражение 3 goto cycle;

}

В качестве "выражения!" и "выраженияЗ" можно использовать списки выражений, в которых выражения разде^лены запятыми.

Оператор for

 

 

 

 

 

 

о Выражение_2

 

 

 

 

 

>j Выражение_1

 

 

 

 

 

 

 

 

 

• о

Оператор

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Выражение_3

 

 

 

 

 

 

 

 

 

Рис. 39. Синтаксическая диаграмма оператора/Ьг

 

/ /

пример

 

namel

 

20 ]

=

"Кафедра

АВТ"^

 

 

char

 

 

 

 

 

 

int

 

 

 

kaf__name [ 20

];

 

 

 

 

 

 

1;

 

 

 

 

 

 

 

 

// Копирование

пате

в

kaf_name

с использованием

цикла

for

fori

i =

0;

пате[

i

]

!=

'\0';

i + +

)

 

 

{

kaf_name

[

i

]

= name [

i

]/

 

 

 

 

 

 

 

}

name[

i

]

=

'\0'

/

 

 

 

 

 

 

kaf

 

 

 

 

 

 

105

//

Копирование

name

в

kaf_name

с использованием

 

цикла

while

//

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

 

 

управляющей

переменной

 

цикла

 

 

1

-

О/

 

i ]

 

 

 

 

 

 

 

 

 

 

 

while

(

пате[

 

!=

'\0'

)

 

 

 

 

 

 

{

 

kaf__name[

i

]

=

name

[ i

];

 

 

 

 

 

 

 

 

 

 

 

 

 

 

//

Модификация

 

управляющей

переменной

цикла

 

 

 

 

±++;

 

 

 

 

 

 

 

 

 

 

 

 

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

kaf_name[

i ]

==

'\0'/

 

 

 

 

 

 

 

 

//

В

качестве

упражнения

 

предлагается

 

этот

же

фрагмент

 

//

 

записать

с

использованием

цикла

 

do-whlle

 

 

//

В

заключение

 

выполним

 

копирование

строк

с

использованием

//

 

строковой

функции

St

г еру

(подробнее

о

строковых

функциях

//будет сказано ниже)

^include

<string.h>

 

// Для строковых

функций •

strcpy

( kaf__name,

name

) ;

 

Из рассмотренного

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

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

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

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

for( ; ; ) оператор // Бесконечный цикл

Как и для циклов while и do-while, для цикла for последова­ тельность передачи управления в теле цикла может быть изменена с помощью операторов break и continue (рис. 40).

106

for( выр1; выр2; вырЗ )

for( выр1; выр2; вырЗ )

{

{

break;

continue;

} Передача управления на «выражениеЗ» - см. эквивалентное представление

Рис. 40. Использование операторов break и continue в цикле/Ьг

Пример. Одномерный массив вещественного типа напечатать по

четыре элемента в строку по 15 позиций на элемент

JV

^define

N100

 

 

 

 

//

Размер

массива

 

^include

<stdlo.h>

 

//

Для

функций

ввода-вывода

{

 

 

 

 

 

 

 

 

 

 

 

float

 

а[

N ]/

//

Массив

для печати

printf(

"\п"

) ;

 

//

Начать

печать

с новой строки

for(

int

i

=

О;

1

< N;

i-f-f

;

 

 

{

±f(

(

1

% 4

)

== 0

)

printf(

"\n"

) ;

 

 

pr±ntf(

 

"%15g", a[

i

]

) ;

 

 

}

 

 

 

 

 

 

 

 

 

 

 

}

 

 

 

 

 

 

 

 

 

 

 

В качестве упражнения рекрмендуем Вам запрограммировать эту же задачу с использованием циклов while и do-while.

Повторно напоминаем, что в языке C++ в блоке можно чередо­ вать определения объектов и операторы, но определение объекта

обязательно должно

предшествовать его использованию в операто­

ре. В рассмотренном

примере таким объектом является /. Область

действия и время жизни / - от точки определения (заголовок цикла) и до конца блока (объект с автоматическим классом хранения).

Завершая рассмотрение циклических операторов, отметим, что при программировании цикла есть три возможности:

использовать цикл/Ьг;

использовать цикл while;

использовать цикл do-while.

Возникает вопрос: какой из этих альтернатив следует восполь­ зоваться в конкретном случае? Ответ прост - лучше всего, как было показано выше, использовать цикл for, а это всегда можно сделать,

107

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

4.11. Оператор goto и метки операторов

Операторы break и continue определялись выше как операторы с ограниченным диапазоном передачи управления. В дополнение к ним языки Си/С++ предоставляют программисту и нашумевший оператор перехода ^о/'о:

доЬо идентификатор;

Здесь "идентификатор" является именем метки, которая запи­ сывается в виде

идентификатор:

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

следование;

ветвление;

цикл.

Однако существуют ситуации (их немного), когда goto удобен, и поэтому его включили в язык Си. Из числа подобных ситуаций на­ зовем две.

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

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

4.12.Упражнения для самопроверки

1.Изобразить фрагмент схемы программы, соответствующий сле­ дующему фрагменту Си-программы:

108

if(

с =^

1

)

а + + /

else

±f( с

2 ) а-

else

±£(

с

=^

3 )

а +=

1/

 

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

{

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

{

lf( /* Ошибка */... ) goto loop_end;

(oop_end:

<

Рис. 41. Использование оператора go/^о для выхода из гнезда циклов

2. Записать фрагмент программы, соответствующий следующему фрагменту схемы программы (выполнить действие, противоположное предыдущему):

<^а <= Ь ^ Нет

г:=3;

i к

1 Да

к:=п;

г:= 1;

3. с помощью операторов ветвлений и присваивания записать на языке Си фрагмент программы, вычисляющий величину

[

п+1

при

1=4,

9,

п ^ [

а+Ь

при

i='l, 1,

[

а-Ь

в остальных

случаях

4. Пусть определена переменная

int

к;

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

printf(

"\п

%5s \ л " ,

'"*-" ) ;

for( к =

1;

к

>=

-5;

к--

)

printf(

 

"

%li

%3s

",

к, "--" ) ;

109