Б. Страуструп - Язык программирования С++. Специальное издание, 3-изд. Бином. 2004 (1160791), страница 33
Текст из файла (страница 33)
(*1) Напишите функцию, которая обменивает значения двух целых чисел. В качестве типа аргумента воспользуйтесь 1п1*. Напишите аналогичную функцию с аргументом типа (п(&. 5. (*1.5) Каков размер массива я1г в следующем примере: сЬагя1гЦ ="короткая строки', Какова длина строки "короткая строка"". 6. (*1) Определите функцииу(сйаг], д(сйаг&] и Ь]сопягсйагс4. Вызовите их с аргуллентал|и 'а', 49, ЗЗОО, с, ис ы яс, где с — сЬаг, ис — ипя(унес( сЬаг и яс — ящпеОсЬаг. Какие вызовы допустимы? При каких вызовах компилятор создаст временные переменные'? 7.
(*1.5) Определптс таблицу, содержащую название месяпев н количество дней в каждом пз них. Выведите содержимое таблицы. Проделайте это дважды: первын раз воспользуйтесь массивом символов для имен п массивом целых для дней, а второй раз воспользуйтесь массивом структур, каждая нз которых хранит названые месяца и количество дней в ием.
8. (*2) Выполните какие-нибудь тесты, чтобы убедиться, что ваш компилятор создает эквивалентные коды для итераций по индексу и с указателем (9 53.1). Если у компилятора есть несколько уровней оптимизации, посмотрите, как это влияет на качество сгенерированного кода. 9. ("1.5) Найдите пример, когда имеет смысл воспользоваться именем в его собственном инициализаторе. 10. ("1) Определите массив строк, в котором строки содержат названия месяцев. Распечатайте эти строки. Передайте массив в функцию, которая печатает строки.
146 Глава 5. Указатели, массивы и структуры ! 1. (*2) Прочитайте последовательность слов из потока ввода. Пусть слово Яп1( будет означать конец ввода, Распечатайте слова в порядке их ввода. Исключите из печати одинаковые слова. Отсортируйте слова перед печатью. 12. (*2) Напишите функцию, подсчитывающую количество вхожлений пар букв в строку ятНпд. Напишите функцию, которая делает то же самое в массиве символов, отраннченном нулем (в С-строке).
Например, пара "аЬ" дважды встречается в "хаЬаасЬахаЬЪ". 13. ('1.5) Определите структуру 2)а1е для хранения дат. Напишите функции, которые читают даты из потока ввода, выводят даты и инициализируют переменные типа 2)а(е. Выражения и инструкции Преждевременная олгни.низадия— корень всех зол. — Д. Кнугп С другой стороны, мы не мазне и игнорировать зффектиеность — Джонатан Бентли Пример с калькулятором — ввод — параметры командной строки — обзор операторов — логические и реляционные операторы — ннкремент и дскремент — свободная память — явное преобразование типов — сводка инструкций — объявления — инструкции выбора — объявления в условнях выбора — итерации — пресловутый до1о — комментарии н отступы советы — упражнения.
6.1. Калькулятор Мы рассмотрим инструкции п выражения на примере программы-калькулятора, которая полдержпвает четыре стандартных арифметических действия в качестве инфпксных операторов над числамп с плавающей точкой. Кроме того, пользователь может определять переменные. Например, если имеется ввод: «=25 агеа = рг * г' г где р1 — предопределегшая псрсмсппая, программа калькулятора выведет: 25 19 685 где 2.5 является результатом присваивания в первой строке ввода, а 19.555 — результатом второй строки.
Калькулятор состоит из четырех основных частей: синтаксического анализатора (рагзег) нли обработчика, функции ввода, таблицы символов и драйвера (управляющей программы). В действительности, зта программа является миниатюрным компилятором, в котором обработчик осуществляет синтаксический анализ, функция ввода управляет вводом и осуществляет лексический анализ, в таблице символов содержится постоянная информация, а драйвер управляет инициализацией, выводом и обработ- Глава 8. Выражения и инструкции 148 кой опгпбок. Мы могли бы добавить много других средств к этому калькулятору, чтобы он стал более полезным Я 6.6(20]), но, во-первых, код и так будет достаточно велик, а во-вторых, болыцинство средств, полезных для практического калькулятора, просто увеличат размер кода, не добавляя при этом ничего к иллюстрации возможностей С ь+.
б.1.1. Синтаксический анализатор Грамматика языка, воспринимаемого калькулятором, описывается следующим об- разом: ргоугат ЕЛВ ехрг Вв! Е?ИЗ //ЕН — эпю конек ввода ехрг ?сх! //список выражении ехргевмоп Р????чТ // РР??чр — эсно точна г зоил той ехргеввсоп Р???с?Т ехрг ??и! О выра жение ехрс евв?оп ехргевв?ои» гегсн ехргеввсоп — гегт гепп // терл гегт гегт / рп тату гегт "рптагу рптагу О первичное выра жение // число // имя ргйлагу !»с?/МВЕ?? МАМЕ ?чАМЕ = ехргеев?оп — р> ипагу (ехргеев!оп! Иными словами, программа есть последовательность выражений, разделенных точкой с запятой.
Ьазовые элементы выражений — это числа, имена, операторы *, /, +,— Гунарный и бинарный) н =. Илсена не обязательно объявлять до их использования. Применяемый нами с гсись синтаксического анализа обычно называсот рекурсивным гнусном — это довольно популярная и «прозрачссая» техника анализа «сверху вниз». В таких языках, как С++, где вызов функций обходится довольно дешево, эта техника егде и эффективна.
Для каждого грамматического предложенпя имеется функция, вызывающая другие функции. Терминальные символы ?например, ЕН0, А??IМВЕ?Т, + и -) распознаются лексическим анализатором, уе! ?о?ееп ((; нетерминальные символы распознаются функциями синтаксического анализатора ехрг ((, ?егт (( и ргст ((. Как только оба операнда !под)выраженсся становятся известны, вычисляется значение выражения.
В настоясцем компиляторе в этот момент может генерироваться код. Для ввода синтаксический анализатор пользуется функцией де! ?ойеп (( (получить лексему), Резулыат последнего вызова функции де! ?онеп (( хранится в глобальной переменной сит г ?о/е (текугдая лексема). Переменная сип ?ой имеет тпп перечне.лецпя Тайен иа?ие (значение лексемы): 149 6.1. Калькулятор елит Тайен оа1ие) МАМЕ, ХЮМВЕВ, РЕ1<В = 'э',М1МУВ = '-', РВТНТ = ',',А3516й> = '=', Е1>>1>, МЛ.=", Е>Л = Т, ЕР = '~', ВР =')' Тойел иа)ие си<< 1оЬ = РВ!ЯТ, <1оийе ехрг )Ьоо1 де1) ,<,< сложение и вьтитание <1оиЫе 1еТ< = 1егт )де1), >>>< «ве«но» Тог)„) ятисЬ )сиге 1оЬ) ) саве РЕ<>з 1еу< э= 1егт (1<не), Ь<еаЬ, саве МТЛ<1<$ 1е11-= 1егт )1 ие), Ь> еаЬ, <)еТаий ге1игп 1еТ1, ) Эта функция, в действительности, сама по себе делает немного. Как это н принято в высокоуровневых функциях в оолыпнх рограммах, для выполнения реальных действий она вызывает другие функщэи яин1сЬ-инструкиия сравнивает указанное значение (в круглых скобках) с набором констант.
Ьгеай-инстуукцин используется для выхода из инструкции яв11сЬ. Константы, следующие за меткамп саяе, должны отличаться друг от друга. Если проверяемое значение не равно ни одной из констант, выполняется инструкция, указанная после <1е~аи<1. В общем случае программист не обязан задавать <Те~аи11. Представление каждой лексемы в виде целого значения символа, которь>й ее определяет, удобно и эффективно ц может оказаться полезным при использовании отладчика Это работает прн условии, что символы, используемые при вводе, не имеют значений из перечисления епит Тайен иа1ие; ни в одном известном мне используемом наборе символов нет печатных символов, целые значепня которых являлись бы однозначными числами. Начальным значением сиге 1оЬ я выбрал РИЛ1Т, потол>у что :это именно то значение, которое имеет сигг 1оЬ после вычисления значения выражения и вывода результата.
Таким образом я «запусках> систему» в нормальном состоянии, минимизируя вероятность ощпбки н потребность в специальном инициализирующем коде. Каждая функция синтаксического анализатора принимает логический Я 4.2) аргумент, который указывает, должна тп зта функция вызывать де1 1оЬеп () для выделения следующей лексемы из входного потока. Каждая функция синтаксического анализатора вычисляет значение <всего» выражения и возвра>цвет его. Функция ехрг () обрабатывает сложение и вы пп анне.
Она состоит нз простого цикла, осуществляющего поиск тсрмов для сложения и вычитания: Глава 6. Выражения и инструкции 150 Обратите внимание, что выражения типа 2 — 3+4 в соответствии с определениеи грамматики вычисляются как (2-3)«4. Странная запись!ог(„) является стандартным способом задания бесконечного цикла Вы можете читать это как «бесконечное количество разы Такая запись является выроя< денной формой уог-ингтрукс(ии Ц 63.3); другой альтернативой является выражение гоЫ!е (ггие). Инструкция зей!сй выполняется до тех пор, пока не найдено что-нибудь отличное от+ н —, после чего выполняется ге!ага-инстлррхция, следующая за г!е~аи!! Операторы «-= и -= использованы для выполнения сложения и вычитания. Можно было записать !е~1=!еЯ«!егт (!гие) и !еЯ=!еу1-1еггп (1!т!е), что не привело бы к нзхшнению работы программы.
Однако запись !е~Р- 1егт (1гие) п !е!)-=1егт (1гие) не только короче, но и выражает необходимые действия в более непосредственной форме. Каждый оператор присваивания является отдельной лексемой, поэтому а ' = 1 является синтаксической ошибкой пз-за пробела между+ и =. Операторы присваивания определены для бинарных операторов % х ( " «» поэтому допустимы следующие операторы присваивания — «= »= М -- оператор деления по модулю (то есть остаток). 8, ( и " — битовые логические операторы И, ИЛИИ исключающее ИЛИ.
«и» — операторы сдвига влево и вправо В з 6.2 представлена сводная информация об операторах. Выражение хР=у означает х=хц у, если операнды имеют встроенные типы, за той лишь разницей, что х вычисляется только один раз. В главах 8 и 9 обсуждается организация программы в виде набора модулей. За одним исключением все объявления в нашем примере можно упорядочить таким образом, что все будет объявлено одни раз и до использования. Исключение составляет ехрг(), которая вызывает 1егт (), которая вызывает рйт (), которая в свою очередь вызывает ехрг (). Этот замкнутый круг надо каким-нибудь образом разорвать.
Объявление с!вийе ехрг (Ьоо!), до объявления рг!т () прекрасно решает эту проблему. Функция 1егт () обрабатывает умножение и деление аналогично тому, как ехрг() делает это со сложением п вычитанием: 1! улноженае и деление с!оийе 1егт (Ьоо!дег) ( с!вийе !еу! = рнт (дег), аког („) /1 «вечно> вш!1«Ь (сигг 1оя) ( ' М(!1. !с!1'= рпт (ггие), Ьгеай, сазе !ЭЛг Ц (с!ои Ые д = р г!т (1гие)) ( !ей /= с(, Ьгеад, 151 5 Л . Калькулятор ге1игп еггог("деление на О"); де/пий: ге1ига 1е/б // псрвичньсе вираженсн доиЫе ргпл (Ьоо! де!) ( !/(яе1 яе! !одел (); зсос1сЬ (сш.г 1ой) ( созе Гч'ЮМВЕРс // константа с изоваюи!ей псочкой ( доиЫео=питЬег иа!ие; яе1 !одел(); ге!игл о; саяезУАМЕ ( доиЫеЬ о = гаЫе(я!пни иа1ие); !/ (уе1 !одел ,') = — -АЯИ6Л", о = ехрг (1гие), ге1игл о; сазе Я1сУ(!$.