1629295403-b876e2087bddebea4bc9666fb2377a02 (846199), страница 20
Текст из файла (страница 20)
Такой цикл не только проще для чтения и понимания, но и для проверки егокорректности — вспомните, что основная ошибка при работе с циклом w h i l e — забытое увеличение счетчика или некорректный критерий завершения цикла. Недаром циклfor встречается в программах на порядок чаще других разновидностей циклов.Так уж сложилось, что в основном в первой части цикла f o r выполняется инициализация переменной-счетчика, а в последней — ее увеличение. Но это неболее чем традиция — С# не требует этого от программиста.
В этих двух частях цикла f o r можно выполнять какие угодно действия, хотя, конечно же, длятого чтобы отойти от традиционной схемы, нужны серьезные основания.В цикле f o r особенно часто используется оператор инкремента (который вместес другими операторами был описан в главе 4, "Операторы"). Обычно приведенный ранеецикл for записывается какfor(int n Y e a r = 1;nYear < n D u r a t i o n ;nYear++){//...т е л о цикла.. .}Почти всегда в цикле f o r применяется постфиксная форма оператора инкремента, хотя в данном случае функционально она идентична префиксной.4У цикла f o r имеется одно правило, которое я не в состоянии пояснить — если условие в цикле отсутствует, считается, что оно равно t r u e .5Таким образом, f or (; ;) —такой же бесконечный цикл, как и w h i l e ( t r u e ) .В реальных программах f o r (; ;) в качестве бесконечного цикла используетсязначительно чаще, чем w h i l e ( t r u e ) ; но чем это вызвано, объяснить сложно.4К счастью, современные компиляторы достаточно интеллектуальны, чтобы понять, что вданном случае возвращаемое значение не играет никакой роли, и не выполнять дополнительнойработы по сохранению начального значения переменной при использовании постфиксной формыоператора.
— Примеч. ред.5Это правило легко пояснить тем, что если бы отсутствие условия воспринималось какfalse, то в таком цикле выполнялась бы исключительно первая часть заголовка, но не последняяи не тело цикла. — Примеч. ред.Глава 5. Управление потоком выполнения105Вложенные циклыОдин цикл может находиться в теле другого цикла:for(...некотороеусловие...){for(...некотороедругоеусловие...){//...какие-тодействия...Внутренний цикл выполняется полностью при каждом выполнении тела внешнейцикла. Переменная-счетчик цикла, используемая во внутреннем цикле, является неопределенной вне области видимости внутреннего цикла.Цикл, содержащийся внутри другого цикла, называется вложенным (nested)Вложенные циклы не могут "пересекаться", т.е. приведенный далее исходнытекст некорректен:Трудно даже предположить, что бы мог означать такой код, но это и неважно — всеравно такой код будет немедленно забракован компилятором.Оператор b r e a k внутри вложенного цикла прекращает выполнение только этапвложенного цикла.
В приведенном далее фрагменте исходного текста оператор brea)завершает работу цикла Б и возвращает управление циклу А://Циклfor(...for Анекотороеусловие...){/ / Цикл f o r Бfor(...некотороедругоеусловие...){//if{. . . некоторые действия(Истинное условие)break;//Выход и з...циклаБ,нонеизцикла А}}}В С# нет команды, которая бы обеспечивала одновременный выход из обоих циклов. |Это не настолько уж большое ограничение, как могло бы показаться. На практике зачастую сложную логику, содержащуюся внутри таких вложенных циклов, лучше инкапсулировать в виде функций.
Выполнение оператора r e t u r nв любом месте обеспечивает выход из функции, т.е. из всех циклов, какой быни была глубина вложенности. Функции и оператор r e t u r n будут рассматриваться в главе 7, "Функции функций".106Часть II. Основы программирования в С#В приведенной далее программе D i s p l a y X W i t h N e s t e d L o o p s , которуюможно назвать шуточной, пара вложенных циклов используется для того,чтобы вывести на экран большую букву X.II D i s p l a y X W i t h N e s t e d L o o p s// Использует п а р у вложенных ц и к л о в// большой буквы Xusing S y s t e m ;длявыводана э к р а нnamespace D i s p l a y X W i t h N e s t e d L o o p s{publicclassProgram{publics t a t i c void Main(string[]args){int nConsoleWidth = 4 0 ;// Итерация по строкамf o r ( i n t nRowNum = 0 ;nRowNum < n C o n s o l e W i d t h ;nRowNum + = 2){// Итерация по столбцамf o r ( i n t nColumnNum = 0 ;inColumnNum < n C o n s o l e W i d t h ; nColumnNum++){/ / П о умолчанию и с п о л ь з у е т с я1 1char с =;пробел// Е с л и н о м е р с т р о к и и с т о л б ц а с о в п а д а ю тif (nColumnNum == nRowNum).
. .{/ / . . . заменим пробел обратной косой ч е р т о йс = ' \\ ' ;}// Если с т о л б е ц на противоположной// с т о р о н е с т р о к и . . .i n t nMirrorColumn = nConsoleWidth i f (nColumnNum = = n M i r r o r C o l u m n )nRowNum;{/ / . . . заменим пробел к о с о й чертойс = ' /1 ;}// Вывод с и м в о л а вConsole.Write(с);текущей позиции}Console.WriteLine();}//Ожидаем п о д т в е р ж д е н и япользователяГлава 5. Управление потоком выполненияSi107Сначала вычисляется выражение в круглых скобках после оператора s w i t c h . В данном случае это просто значение переменной n M a r i t a l S t a t u s . Затем вычисленщзначение сравнивается со значениями у каждого из операторов c a s e . Если нужное значение не найдено, управление передается операторам, следующим за меткой d e f a u l t .Аргументом оператора s w i t c h может быть также строка s t r i n g :string s = "Davis";switch(s){case "Mallory":/ / Некоторые д е й с т в и яbreak;case "Wells":/ / Некоторые д е й с т в и яbreak;case"Arturo":/ / Некоторые д е й с т в и яbreak;c a s e "Brown":/ / Некоторые д е й с т в и яbreak;default:// Действия, если такой/ / фамилии н е т в с п и с к е}При применении конструкции s w i t c h действует ряд ограничений.S Аргументstring.оператораs w i t c h ()должениметьперечислимыйтипили типSНельзя использовать числа с плавающей точкой.^Значения c a s e должны иметь тот же тип, что аргумент оператора s w i t c h .SЗначения c a s e должны быть константами в том смысле, что их значения должныбыть известны во время компиляции.SКаждая конструкция c a s e должна завершаться оператором b r e a k (или какой-тоиной командой выхода, например, r e t u r n ) .
Оператор b r e a k передает управление за пределы конструкции s w i t c h .Допускается наличие нескольких c a s e для одного блока кода, как в следующем примере:switch(nMaritalStatus){c a s e 0 .case 2:// Действия для холостяков/незамужних// р а з в е д е н н ы х одни и те жеbreak;case 1:// Действия для семейныхbreak;110идляЧасть II. Основы программирования в С#case 3 :// Действия для в д о в ( ц о в )break;case 4:/ / Действия для н е и з в е с т н о г о с е м е й н о г о с о с т о я н и яbreak;default:// Д е й с т в и я , к о г д а переменная принимает з н а ч е н и е ,/ / о т л и ч а ю щ е е с я о т в с е х п е р е ч и с л е н н ы х выше - п о в с е й/ / видимости, э т о о з н а ч а е т , что произошла к а к а я - т о/ / ошибкаbreak;}Управление может быть передано в другую точку при помощи оператора безусловного перехода g o t o .
За этим оператором может следовать:метка;c a s e в конструкции s w i t c h ;ключевое слово d e f a u l t , обозначающее блок d e f a u l t в конструкции s w i t c h .Два последних случая предназначены для перехода от одного блока c a s e к другому вконструкции s w i t c h .Вот пример применения оператора g o t o :// Если у с л о в и е и с т и н н о . .
.if (а > Ь)II'/ / Управление о п е р а т о р о м g o t o п е р е д а е т с я// расположенному за меткой e x i t L a b e lgoto e x i t L a b e l ;коду,// Некоторый программный к о дexitLabel:// Управление п е р е д а е т с я в э т у т о ч к уОператор g o t o крайне непопулярен по той же причине, по которой он являетсяочень мощным средством — в силу его полной неструктурированности. Отслеживаниепереходов в нетривиальных случаях, превышающих несколько строк кода, — крайне неблагодарная задача.
Это именно тот случай, когда говорят о "соплях" в программе.Вокруг применения g o t o ведутся почти "религиозные войны". Доходит докритики С# просто за то, что в нем есть этот оператор. Но на самом деле в немнет ничего ужасного или демонического. Другое дело, что его применения следует избегать, если в этом нет крайней нужды.Глава 5. Управление потоком выполнения111Одно дело — объявить переменные там и сям, и складывать их, и вычитать. И совсем другое — писать реальные программы, которымиможет пользоваться еще кто-то.
В этой части речь пойдет о том, какгруппировать данные и работать с ними. Вы научитесь думать о программах как о наборе сотрудничающих объектов и приступитек созданию собственных объектов. Это заложит основу для всей вашейбудущей деятельности в качестве программистов.Глава 6Объединение данных классы и массивы> Введение в классы С#> Хранение данных в объектах> Ссылки на объекты> Создание массивов объектовы можете свободно объявлять и использовать все встроенные типы данных —такие как i n t , d o u b l e или b o o l — для хранения информации, необходимойвашей программе. Для ряда программ таких простых переменных вполне достаточно, нобольшинству программ требуется средство для объединения связанных данных в аккуратные пакеты.Некоторым программам надо собрать вместе данные, связанные логически, ноимеющие разные типы.