Язык Си - Уэйт, Прата, Мартин. M. уэит с. Прата д. Мартин
Скачать 4.69 Mb.
|
Резюме: операция условия I. Операция условия: ?: В этой операции имеются три операнда, каждый из которых является выражением, причем вся запись выглядит следующим образом: выражение1 ? выражение2 : выражение3. Значение всего выражения равно величине выражения2, если выражение1 истинно, и величине выражения3 в противном случае. II. ПРИМЕРЫ: Выражение: (5 > 3) ? 1 : 2 имеет значение 1 Выражение: (3 > 5) ? 1 : 2 имеет значение 2 Выражение: (а > b) ? a : b имеет значение большей из величин а и b. МНОЖЕСТВЕННЫЙ ВЫБОР: ОПЕРАТОРЫ switch И break Далее Содержание 141 Операция условия и конструкция if-else облегчают написание программ, в которых осуществляется выбор между двумя вариантами. Однако иногда в программе необходимо произвести выбор одного из нескольких вариантов. Мы можем сделать это используя конструкцию if-else if - ... - else, но во многих случаях оказывается более удобным использовать оператор switch. Ниже приводится пример, иллюстрирующий его работу. Программа читает с терминала букву, затем выводит на печать название животного начинеющееся с этой буквы. /*животные*/ main( ) { char ch; printf("Введите букву алфавита, а я укажу"); printf("название животного, \n начинающееся с нее.\n"); printf("Введите, пожалуйста, букву; для завершения работы введите #. \n"); while((ch = getchar())!= '#') { if(ch != '\n') /* пропуск символа "новая строка" */ { if(ch >= 'a' && ch <= 'я') /*разрешены только строчные буквы */ switch (ch) { case 'a' : printf(" аргали, дикий горный азиатский баран\n"); break; case 'б' : printf(" бабирусса, дикая малайская свинья \n"); break; case 'в' : printf(" выхухоль, водоплавающий крот \n"); break; case 'г' : printf(" гиббон, длиннорукая обезьяна \n"); break; case 'д' : printf(" даман древесный \n"); break; default: printf(" Это трудная задача!\n"); break; } else printf(" Я распознаю только строчные буквы. \n"); printf(" Введите, пожалуйста, следующую букву или #.\n"); } /* конец if, пропускающего символ "новая строка" */ } /* конец цикла while */ } РИС. 7.7. Программа, печатающая названия животных. Нам стало скучно продолжать, и мы остановились на букве д. Давайте теперь рассмотрим один пример выполнения программы перед тем, как обсудить использованные в ней новые средства языка. Введите букву алфавита, а я укажу название животного, начинающееся с нее. Введите, пожалуйста, букву; для завершения работы введите #. а [возврат] аргали, дикий горный азиатский баран Введите, пожалуйста, следующую букву или #. г [возврат] гиббон, длиннорукая обезьяна Введите, пожалуйста, следующую букву или #. р [возврат] Это трудная задача! Введите, пожалуйста, следующую букву или #. Т [возврат] Я распознаю только строчные буквы. Введите, пожалуйста, следующую букву или #. # [возврат] Этот пример служит иллюстрацией работы оператора swith. Вначале вычисляется выражение в скобках, расположенное за ключевым словом switch. В данном случае значением этого выражения будет символ, присвоенный переменной ch, который мы ввели перед этим. Затем программа просматривает список "меток" (в этом примере case 'a':, case'б': и т. д.) до тех пор, пока не находит "метку", которая соответствует данному значению. Далее программа переходит к выполнению оператора, расположенного в этой строке. Что произойдет в случае, когда такой подходящей строки не найдется? Если существует строка с "меткой" case default:, то будет выполняться оператор, 142 помеченный этой меткой. В противном случае произойдет переход к оператору, расположенному за оператором switch. Что можно сказать по поводу оператора break? Его выполнение приводит к тому, что в программе происходит выход из оператора switch и осуществляется переход к следующему за ним оператору (см. рис. 7.8). При отсутствии оператора break будут выполнены все операторы, начиная с помеченного данной меткой и завершая оператором switch. Если удалить все операторы break из нашей программы, то, указав, например, букву г, получим следующий диалог: Введите букву алфавита, а я укажу название животного, начинающееся с нее. Введите, пожалуйста, букву; для завершения работы введите #. г [возврат] гиббон, длиннорукая обезьяна даман древесный это трудная задача Введите, пожалуйста, следующую букву или #. # [возврат] Мы видим, что выполнились все операторы, начиная от метки case 'г' и кончая оператором switch. Если вы знакомы с языком Паскаль, то можете заметить, что оператор switch в Си похож на оператор case в Паскале. Важнейшее отличие состоит в том, что если вы хотите, чтобы в каждом конкретном случае выполнялся только помеченный оператор, то в операторе switch необходимо использовать операторы break. Метки, имеющиеся в операторе switch, должны быть константами или константными выражениями (выражения, операнды которого константы) целого типа (включая тип char). Запрещается использовать в качестве метки переменную. Значением выражения в скобках должна быть величина целого типа (опять же, включая тип char). Ниже приводится общая структура оператора switch: switch(целоe выражение) { case константа1 : операторы; (необязательные) case константа2 : операторы; (необязательные) case default (необязательные) : операторы; (необязательные) } switch (number) { case 1: оператор 1; break; case 2: оператор 2; break; сазе 3: оператор 3; break; default:оператор 4; } оператор5; switch (number) { case 1: оператор 1; case 2: оператор 2; case 3: оператор 3; defauit: оператор 4; } оператор 5; В обоих случаях значение number равно 2. РИС. 7.8. Ход выполнения программы, использующей оператор switch при наличии или в 143 отсутствии операторов break Когда мы хотим получить одинаковый результат при переходе к разным меткам, мы можем использовать метки без операторов. Например, фрагмент программы case 'E': case 'e': printf(" ехидна, муравьед колючий \n" ); break; свидетельствует о том, что указание букв Е или е приводит к печати названия "ехидна". Если будет введена буква Е, то произойдет переход к соответствующей метке, но, поскольку там операторы отсутствуют, будут вы полняться операторы, расположенные ниже, пока не встретится оператор break. Наша программа имеет две небольшие особенности, о которых мы хотели бы упомянуть. Первая поскольку мы собираемся использовать программу в диалоговом режиме, мы решили воспользоваться символом # вместо EOF в качестве признака прекращения ее работы. В работе компьютера могли бы возникнуть сложности, если бы он предложил нам ввести признак EOF или даже какой-нибудь управляющий символ, между тем как символ # вполне подходит для этой цели. Поскольку теперь отсутствует необходимость чтения символа EOF, мы не должны описывать в программе переменную ch типа int. Вторая мы использовали оператор if, который позволяет игнорировать символы "новая строка" при вводе символов в программу. Это тоже некоторая плата за возможность диалоговой работы. Без этого оператора if каждый раз при нажатии клавиши [возврат] программе пришлось бы рассматривать данный признак как прочитанный символ. Когда требуется использовать оператор switch, а когда конструкцию else-if? Часто у нас нет возможности выбора. Вы не можете применить оператор switch, когда выбор вариантов основывается на вычислении значения переменной или выражения типа int. Удобного способа воспользоваться оператором switch в случае когда возможные значения переменной попадают в некоторый диапаон, также не существует. Проще написать, например, так: if(integer < 1000 && integer > 2) В то время как замена этой строки оператором switch приведет к необходимости ввести в программу метки для всех целых чисел от 2 до 999. Тем не менее, если у вас есть возможность применить оператор switch, ваша программа будет выполняться более эффективно. Резюме: множественный выбор вариантов с помощью оператора switch Управление в программе передается оператору, у которого в качестве метки используется значение некоторого выражения. Затем в процессе прохождения программы будут выполняться оставшиеся операторы, пока не произойдет новый переход. Как выражения, так и метки должны иметь значения целого типа (включая тип char), метки должны быть константами или константными выражениями. Если не которому значению выражения не соответствует никакая метка, управление передается оператору с меткой default (если такой имеется). Впротивном случае управление передается оператору, следующему за оператором switch. III. Форма: switch (выражение) { case метка1: оператор1 144 case метка2: оператор2 default: оператор3 } В операторе может присутствовать более чем 2 помеченных оператора, а наличие метки default является необязательным. IV. Пример switch (letter) { case 'a': case 'e': printf(" %c - это гласная \n ", letter); case 'c': case 'n': printf(" Символ %с в наборе букв \ саnе\ n ", letter); default: printf(" Добрый день. \n" ); } Если переменная letter имеет значение 'a' или 'e', будут выведены на печать все три сообщения, если же 'c' или 'n', то последние два. В случае остальных значений будет напечатано только последнее сообщение. Изложенный здесь материал позволит вам писать гораздо более мощные и обладающие большими возможностями программы, чем раньше. В справедливости этого утверждения вы сможете убедиться, если сравните некоторые из примеров, приведенных в данной главе, с программами, рассмотренными в предыдущих главах. Но вы изучили еще далеко не все. Вот почему вам придется одолеть еще немало страниц этой книги. ЧТО ВЫ ДОЛЖНЫ БЫЛИ УЗНАТЬ В ЭТОЙ ГЛАВЕ Далее Содержание Как осуществить выбор из двух возможностей выполнить оператор или пропустить его: с помощью оператора if. Как осуществить выбор одного из двух вариантов: с помощью оператора if-else. Как осуществить выбор одного из нескольких вариантов: с помощью операторов else-if, switch Операции отношения: > >= = = <= < != Логические операции: && || ! Операция условия: : ? ВОПРОСЫ И ОТВЕТЫ Содержание Вопросы 1. Определите, какие выражения истинны, а какие ложны. а. 100 > 3 б. 'а' > 'с' в. 100 > 3 && 'а' > 'с' г. 100 > 3 || 'a' > 'с' д. !(100 > 3) 2. Запишите выражения, соответствующие следующим условиям а. Значение number равно или больше 1, но меньше 9 б. Значение ch не равно q или k в. Значение number лежит между 1 и 9, но не равно 5 г. Значение number не лежит между 1 и 9 145 3. В программе, приведенной ниже, наряду с неоправданно сложными условными выражениями имеются и прямые ошибки. Уточните эту программу и исправьте в ней ошибки. main( ) /* 1 */ { /* 2 */ int weight, height; /* вес в фунтах, рост в дюймах */ /* 4 */ scanf('' %d, weight, height); /* 5 */ if(weight < 100) /* 6 */ if (height >= 72) /* 7 */ printf(" Для такого веса у вас слишком большой рост \n"); else if (height < 72 && > 64) /* 9 */ printf(" У вас большой рост для вашего веса. \n" ); else if (weight > 300 && !(weight < = 300)) /* 11*/ if( !(height >= 48) /* 12 */ printf(" Для такого веса у вас слишком маленький рост.\n" ); else /* 14 */ printf(" У вас идеальный вес. \n"); /* 15*/ /* 16 */ } Ответы 1. Выражения истинны в вопросах а и г 2. a. number > = 1 && number < 9 б. ch != 'q' && ch != k Замечание: выражение ch != q || ch!= k всегда будет иметь значение "истина", потому что если переменная сh равна q, то она не может равняться k, и второе условие оказывается выполненным врезультате все выражения "ИЛИ" будет истинным. в. number > 1 && number < 9 && number != 5 г. !(number > 1 && number < 9) или number < = 1 || number > = 9 Замечание: сказать, что число НЕ лежит между 1 и 9 это то же самое, что сказать: число равно или меньше 1 ИЛИ равно или больше 9. Вторая форма несколько неуклюже звучит на словах, но проще записывается в виде выражения. 3. Строка 5: должна выглядеть так scanf(" %d %d", &weight, &height). He забывайте указывать символы в качестве префиксов имен переменных в функции scanf( ). Кроме того, данной строке должна предшествовать строка, предлагающая ввести данные. Строка 9: подразумеваемое выражение должно выглядеть так: (height < 72 && height > 64). Однако первая часть этого выражения необязательна, поскольку величина height, если поток управления достигнет записи else-if, будет обязательно меньше 72. Поэтому более простое условие (height > 64) в данном случае служит той же цели. Строка 11: избыточное условие; второе подвыражение (отрицание условия "величина weight меньше или равна 300") означает то же, что и первое. В действительности данное условие записывается так: (weight > 300). Но неприятности на этом не кончаются. Строка 11 относится к ошибочному оператору if. Очевидно, что эта часть else ассоциируется с оператором if, расположенным в строке 6, но, согласно правилу, связывающему ее с ближайшим отрицанием условия, содержащегося в if, она будет ассоциироваться с оператором if на строке 9. Поэтому условие, помещенное на строке 11, будет проверяться в том случае, когда величина weight меньше 100, а величина height меньше или равна 64. Это делает невозможным превышение переменной weight значения 300 при выполнении данного оператора. Строки 7-9 должны быть заключены в фигурные скобки. Тогда строка 11 станет альтернативой оператору, расположенному на строке 6, а не на строке 9. Строка 12: данное выражение необходимо упростить так: (height < 48) Строка 14: это ключевое слово else относится к последнему оператору if, раcположенному на 146 строке 12. Операторы, помещенные на строках 12 и 13, необходимо заключить в фигурные скобки, тогда else будет относиться к оператору if на строке 11. Обратите внимание, что последнее сообщение будет напечатано для тех, чей вес заключен между 100 и 300 фунтами. 1) В программу входит слово score - счет (в игре) - Прим. перев. 2) См. перевод на с. 154 - Прим. ред. 3) В нем используется слово legs - ноги - Прим. перев. 4) В оригинале - игра слов complex (англ.) - сложный и комплексный - Прим. перев. ЦИКЛЫ ВЛОЖЕННЫЕ ЦИКЛЫ ОСУЩЕСТВЛЕНИЕ ПЕРЕХОДОВ В ПРОГРАММЕ ИСПОЛЬЗОВАНИЕ ЦИКЛОВ ПРИ РАБОТЕ С МАССИВАМИ КЛЮЧЕВЫЕ СЛОВА whilе, do, for, break, continue, goto ОПЕРАЦИИ += -= *= /= %= При усложнении решаемых задач ход выполнения программ становится более запутанным. Чтобы иметь возможность управлять процессом выполнения программ и его организацией, вам попадаютя структуры и некоторые специальные операторы. Язык предоставляет эффективные средства реализации таких требований. Мы уже смогли убедиться в чрезвычайной ценности цикла if в том случае, когда необходимо повторить некоторую операцию несколько раз. В языке Си, кроме того, реализовано еще два вида циклов: цикл for и цикл do ... while. В данной главе рассматриваются принципы работы управляющих структур и даются рекомендации, каким образом лучше всего применять каждую из них. Обсудим операторы break, continue, goto и операцию "запятая" все они могут использоваться для управления ходом выполнения программы. Кроме того, мы расскажем вам еще немного о свойствах, которые часто используются вместе с циклами. ЦИКЛ while Далее Содержание В предшествующих главах мы интенсивно пользовались этой формой цикла, сейчас же хотим рассмотреть его работу в случае простой, возможно, даже примитивной программы, угадывающей число. /* угадывание числа1 */ /* неэффективный способ угадывания */ #inlude main( ) { int guess = 1; char response; printf(" Задумайте целое число от 1 до 100. Я попробую угадать"); 147 printf(" его.\n Отвечайте д, если моя догадка правильна и"); printf(" \n н, если я ошибаюсь. \n"); рintf("Итак ... ваше число %d?\n" , guess); while((response = getchar( )) != 'д') /* получение ответа*/ if (response != ' \n') /* пропуск символа "новая строка" */ printf(" Ну, тогда оно равно %d?\n", ++guess); printf(" Я знала, что смогу сделать это!\n"); } Обратите внимание на логику программы. Если вы отвечаете д, в программе осуществляется выход из цикла и переход на завершающий оператор печати. Программа просит вас отвечать и в случае, если ее догадка неверна, но фактически любой ответ, отличный от символа д, приводит к тому, что программа входит в цикл. Однако если введен символ "новая строка", то при данном прохождении тела цикла никаких операций не производится. Получение другого символа приводит к очередной попытке угадывания целого числа. (Что произошло бы в случае использования операции guess++ вместо операции ++guess?). Строка if(response ! = '\n') позволяет программе игнорировать поступление постороннего символа "новая строка", когда вы нажмете клавишу [ввод]. В этом случае тело цикла while не нужно заключать в фигурные скобки, поскольку оператор if, хотя он и занимает две строки в программе, рассматривается как один оператор. Вы, по-видимому, уже заметили, что это довольно "тупая" программа. Она написана правильно и решает поставленную задачу, но делает это крайне неэффективно. Данный пример показывает нам, что правильность написания - не единственный критерий, по которому необходимо оценивать программу. При этом очень важна ее эффективность. Мы вернемся к данной программе несколько позже и попытаемся ее немного улучшить. В общем виде цикл |