Text
                    ПРОФЕССИОНАЛЬНАЯ
РАБОТА
НА ПЕРСОНАЛЬНОМ
КОМПЬЮТЕРЕ


Г. СИМПСОН ПРОФЕССИОНАЛЬНАЯ РАБОТА НА ПЕРСОНАЛЬНОМ КОМПЬЮТЕРЕ
SERIOUS PROGRAMMING FOR THE IBM® PC/XT 7 AT" HENRY SIMPSON TAB BOOKS Inc. Blue Ridge Summit. PA 17214
Г СИМПСОН ПРОФЕССИОНАЛЬНАЯ РАБОТА НА ПЕРСОНАЛЬНОМ КОМПЬЮТЕРЕ Перевод с английского Ю.А. КОБЛЕНЦА-МИШКЕ Предисловие С.В. Черемных МОСКВА "ФИНАНСЫ И СТАТИСТИКА1 1988
ББК 24.4.1 С37 £2405000000—141 010(01)—88 130—88 ISBN 0—8306—0921—0 (США) ISBN 5—279—00065—5 (СССР) © 1985 by Henry Simpson Printed in the United States of America © Перевод на русский язык, предисловие, «Финансы и статистика», 1988
Предисловие к русскому изданию Профессиональное использование персонального компьютера вовсе не предполагает умения программировать. Множество людей в своей работе ограничиваются обработкой текстов на ПК, а так¬ же использованием готовых пакетов прикладных программ. Ни Бейсик, ни какой-либо другой язык программирования здесь не нужен. Можно даже утверждать, что эта категория пользо¬ вателей составляет большинство. Но для того чтобы профессио¬ нально программировать на ПК, уже совершенно необходимо знать ДОС (дисковую операционную систему) и, например, тот же Бейсик. Представляемая читателю книга (дословный перевод названия которой «Серьезное программирование на ПК ИБМ») как раз и знакомит читателя с методологией профессиональ¬ ного программирования, сообщает необходимые сведения о ДОС и Бейсике, что позволяет перейти к решению многих важных про¬ блем программирования. В последнее время вышел ряд публикаций по ДОС [см., например, Хаузер Д., Хирт Дж., Хоукинс Б. Операционная система MS-DOS /Пер. с англ.— М.: Финансы и статистика, 1987. — 168 с.]. Много публикаций и по Бейсику [одна из по¬ следних— Морилл Г. Бейсик для ПК ИБМ/Пер. с англ.— М.: Финансы и статистика, 1987.— 207 с.]. Поэтому требуются до¬ статочно убедительные аргументы, чтобы рекомендовать читателю новую книгу, где Бейсик — едва ли не главный предмет обсуж¬ дения. Мне кажется, в отношении книги Г. Симпсона такие аргументы есть. Стоит на этом остановиться подробнее. Даже поверхностное знакомство с историей Бейсика убеждает в его поразительной жизнеспособности. С 1964 г., момента его создания (вариант Dartmouth BASIC 1 GE 225), разработано больше ста версий. Достоинства Бейсика в сравнении с другими языками программирования известны. Бейсик представляет собой в целом операционную среду. Достаточно войти в нее и можно работать, не задумываясь о том, как функционирует операцион¬ ная система и каковы ее особенности для данного типа ком¬ пьютеров. Развитые версии Бейсика позволяют работать с экран¬ ной графикой и с любыми периферийными устройствами, а опе¬ 5
раторы матричной арифметики облегчают многие серьезные рас¬ четы. Программисту работа на Бейсике дает возможность програм¬ мировать «шаг за шагом» (в соответствии с режимом интер¬ претации), контролировать значения всех переменных, иметь дос¬ туп в любое место памяти (что допускается, хотя и с боль¬ шими трудностями, в других системах программирования). Еще одно полезное свойство языка Бейсик — пошаговое исполнение программ. Если требуется внести в программу изменения и сразу получить результат, Бейсик-интерпретатор — идеальный ин¬ струмент независимо от того, идет ли речь о служебной программе или о компьютерной игре. В то же время замкнутость Бейсик-среды (первые версии) на¬ кладывала сильные ограничения на работу тех пользователей, которые нуждались в постоянном притоке свежих версий при¬ кладных программ по своей тематике, в том числе и на других языках программирования. Появление версии TURBO-BASIC фирмы Borland Internatio¬ nal, отмеченной журналом«Регзопа1 Computing»(Oct. 1987) пер¬ вой в списке лучших программных продуктов 1987 г. по разделу «языки программирования», явилось новым этапом в развитии языка. Эта версия интересна следующим. Сравнение двух попу¬ лярных версий — TURBO-BASIC и Quick-BASIC показывает, что скорость счета при использовании TURBO-BASIC увеличивается в десятки раз. Это закономерно: компиляторы, к которым при¬ надлежит TURBO-BASIC, работают значительно быстрее, чем интерпретаторы ( Quick -BASIC). Кроме того, TURBO-BASIC имеет значительно более широкий набор операторов (будучи сов¬ местимым с Quick -BASIC), более развитый интерфейс (много- оконность, удобная система меню, удобный редактор текста, продуманная система экранной подсказки). К сожалению, TURBO-BASIC не лишен недостатков; главный из них — отсутствие в этой версии средств для создания объект¬ ных модулей. Таким образом, по-прежнему нет возможности работать с библиотеками стандартных программ, разработанных в другой языковой среде. Указанная проблема решена в версии 4 Quick-BASIC — в но¬ вейшей версии MS-DOS компилятора фирмы Microsoft, вполне оправдывающей свое название (quick — быстрый; одна из первых публикаций, посвященных Quick-BASIC, — G. Mishael V о s е, Quick BASIC 4.0. — Byte, November 1987, p. 111 — 114). Эта версия включает средства поддержки модульного програм¬ мирования, а также встроенную программу-отладчик той же фирмы. Пользовательский интерфейс здесь, как и в предыдущих версиях Бейсика, основывается на «оконной» технологии и весьма удобен в работе. Удобен также синтаксический контроль. Ошибка фиксируется сразу же после ввода строки, так что по 6
окончании ввода программа является синтаксически правильной. Quick-BASIC 4.0 может использовать скомпилированные из объ¬ ектных модулей программы на языках С 5.0, QUICK С 1.0, MASM 5.0, PASCAL 3.32 и FORTRAN 4.01. Чтобы вызвать FORTRAN или PASCAL, достаточно прибегнуть к ключевым сло¬ вам самих этих языков. Более подробно с особенностями этой версии Бейсика читатель может познакомиться в упомянутой выше статье или в специаль¬ ных руководствах по Quick-BASIC 4.0. Таким' образом, семейство Бейсиков в последнее время не только пополнилось двумя новыми версиями, но и обогатилось рядом новых качеств, следовательно, еще одна книга о «старом» Бейсике может быть рекомендована широкому кругу читателей, тем более что Бейсик в ней рассматривается не сам по себе, а как элемент технологии «профессионального программирова¬ ния». Можно не сомневаться, что широкая и многообразная аудитория, для которой предназначена эта книга, оценит и педагогическое мастерство автора. В книге 10 глав, 3 приложения и предметный указатель. Содержание первых 8 глав, как ясно из подробного оглавле¬ ния, является достаточно традиционным и комментариев не требует. Две главы книги, касающиеся документирования про¬ грамм (гл. 9) и составления руководств пользователя (гл. 10), стоят несколько особняком. В то же время они заслуживают серьезного внимания. Есть понятия «программа» и «программное обеспечение», это разные понятия. Увеличение выпуска книг и руководств (в том числе и фирм разработчиков «Borland International» и «Micro¬ soft») по отдельным программным продуктам связано в значитель¬ ной степени со стремлением разработчиков превратить программу именно в программный продукт («Software»). Термин «продукт» здесь очень точен, так как он характеризует изделие, пред¬ назначенное для использования другими людьми. Понимание важности вопроса документирования программ для разработчиков и для пользователей во всех его аспектах следует считать элементом культуры современного программиста. Как отмечает автор,.сами программисты часто относятся к состав¬ лению документации как к неизбежному злу, в лучшем случае — как к бюрократической процедуре. При этом среди них нет единого мнения относительно того, кто, собственно, должен доку¬ ментировать программу, в каком объеме и в какой форме. Мне близка точка зрения автора, что процесс документирова¬ ния есть неотъемлемый компонент создания программного про¬ дукта. Следуя этой логике, надо согласиться, что документи¬ ровать программы должен сам программист. Можно привести по крайней мере два довода в пользу этого утверждения. Во-первых, создателю программы легче объяснить другим программистам, как 7
она работает. Во-вторых, документирование — это, в сущности, также забота и о самом создателе программ. Если программисту в силу каких-либо обстоятельств прихо¬ дится возвращаться к своей (недокументированной) программе спустя более или менее длительный срок, он рискует потратить много времени, чтобы разобраться во всех деталях; это время может быть соизмеримо с временем создания всей программы. Бывает, что ряд деталей не удается восстановить совсем. Забы¬ вать — естественное свойство человека. Автор книги предлагает ясные рекомендации по документи¬ рованию программы. Добросовестность, внимание к деталям, последовательность — вот ключевые качества, которые програм¬ мист должен развивать в себе для этой работы. «Будьте последо¬ вательны. Может оказаться, что тот программист, которого вы спасали, это вы сами» — так автор характеризует ситуацию. К сожалению, в отечественной литературе вопросам докумен¬ тирования программ (имеются в виду в первую очередь про¬ граммы для персональных ЭВМ) не уделяется достаточного внимания. Из зарубежных публикаций заинтересованному чита¬ телю можно рекомендовать книгу: Christine Browing. Guide to Effective technical Writing, Prentice-Hall, 1984. Еще более остро, как мне кажется, стоят у нас вопросы, касающиеся документации пользователя, иначе говоря руко¬ водств, в которых объясняется, как, собственно, работать с той или иной программой. Я разделяю точку зрения автора, что качество руководства по программе может в значительной сте¬ пени определить ее судьбу. Вообще излагать результаты своей работы — дело трудное. Писать кратко и ясно, так, чтобы тебя поняли другие,— дело трудное вдвойне. «Извини, матушка, что пишу длинно,— объяс¬ нял Суворов императрице,— писать коротко нет времени». Математики имеют своих классиков в этом вопросе. Статья П. Р. Халмоша «Как писать математические тексты» УМН (т. XXVI, вып. 5(161), с. 243—269) —блестящий образец руко¬ водства, написанного математиком для математиков по одной из труднейших сторон творчества научного работника. Автор представляемой книги в выразительной форме (диалог) дает краткие и ясные рекомендации, как такое руководство должно выглядеть. Это удалось ему, на мой взгляд, только потому, что он выбрал единственно верный ориентир — интересы пользователя, его заботы. «Дружественность интерфейса пользователь — ЭВМ», часто употребляемое в наше время выражение, характеризует взаимо¬ действие человека с компьютером. Степень дружественности опре¬ деляется качеством используемой программы, а именно тем, в ка¬ 8
кой степени цели, профессиональная принадлежность и уровень квалификации пользователя в ней учтены. Закономерно, что автор делает особый акцент на обосновании соотношения между объемами руководств программы: внутрен¬ него (в виде экранной подсказки «help») и внешнего (в виде «manual»). Понятно, что в небольших программах целесообразно применять экранные подсказки, в то время как большие программы нуждаются и в том и в другом виде руководств. Например, широко популярная программа «Graph-in-the box» (New England Software), занявшая первое место в списке лучших програм¬ мных продуктов по разделу «5 наиболее дружественных про¬ грамм» журнала «Personal Computing», Oct. 1987, позволяющая табличные результаты расчетов представить в различных гра¬ фических формах, имеет развитую систему экранной подсказки, а также «внешнюю» документацию в виде руководства. Если экранной подсказки вполне достаточно, чтобы начать работать с данной программой, то «внешнее» руководство дает общее представление о программе, а содержащиеся в нем иллюстративные материалы являются ориентирами для пользо¬ вателя, необходимыми ему для выбора нужного режима работы. Таким образом, эти два вида документации эффективно до¬ полняют друг друга. Главный совет автора разработчикам программ мы должны, ко¬ нечно, принять без колебаний: «Пользователь! Просто пользова¬ тель. Думайте о нем перед тем, как начать писать документацию и во время ее подготовки. Подумайте о нем и после того, как за¬ вершите работу. По возможности испытайте подготовленную вами документацию: дайте ее пользователям и послушайте, что они скажут. Внесите изменения в документацию, основываясь на их замечаниях». Надеюсь, что и книга, и сама технология «профессионального» программирования будут творчески восприняты самой широкой читательской аудиторией. С. В. Черемных
Предисловие Персональный компьютер (ПК) фирмы IBM — очень мощная машина, обладающая большими возможностями. Он стал тем стандартом, с которым сравнивают другие микрокомпьютеры, и породил новую отрасль промышленности, выпускающую для него программы и дополнительное оборудование и изготавлива¬ ющую совместимые1 с ним ПЭВМ. К ПК фирмы IBM, в отличие от большинства персональных компьютеров, никогда не относи¬ лись как к машине для игр и развлечений, даже когда фирма IBM рекламировала модель всего с 16 Кбайт памяти и кассет¬ ным магнитофоном в качестве внешнего запоминающего устрой¬ ства. С самого начала его пользователи — в основном профес¬ сионалы, работающие в сфере мелкого бизнеса, промышленности, образования и в правительственных учреждениях, наращивали свои ПК, чтобы полнее использовать внушительный потенциал машины. Владельцы таких ПК большей частью народ серьезный, и к своим компьютерам они относятся всерьез. Для ПК было создано громадное количество программ. В их числе, конечно, хорошо представлены и игровые и развлека¬ тельные программы, но большая часть программного обеспечения ПК имеет столь же серьезное назначение, сколь серьезен типичный пользователь ПК. Большинство из них куда более за¬ интересовано в обработке электронных таблиц, планировании бюд¬ жета или проведении инженерных расчетов, чем в уничтожении космических пришельцев. Книга будет посвящена главным образом тому, как следует разрабатывать «серьезные» программы. Надеюсь, что эта тема не звучит уныло. В конце концов, слово серьезный означает не скучный, а скорее «то, к чему следует относиться серьезно». В переводе с «программистскогоязыка» на русский «серьезный» будет звучать примерно как «профессиональный». 1 В настоящее время (1988 г.) более 100 фирм выпускают персональные ЭВМ (ПЭВМ), способные выполнять большинство программ, написанных для ПК фирмы IBM (программно-совместимые), а также работать с внешними устройствами и печатными платами, предназначенными для установки в ПК фирмы IBM (совместимость на уровне разъемов). — Примеч. пер. 10
Итак, в этой книге излагаются некоторые общие методы и конкретные приемы построения серьезных программ, в которых проявляется определенная степень профессионализма. Каким требованиям должна удовлетворять серьезная про¬ грамма? Прежде всего от нее требуется дружественность пользова¬ телю. Программу надо сделать надежной и достаточно простой в освоении и в работе. Второе требование — программу необ¬ ходимо спроектировать так, чтобы она была дружественна про¬ граммисту: понятна, хорошо документирована и пригодна для сопровождения1. Серьезная программа полностью использует до¬ ступные ей ресурсы: язык Бе.йсик, DOS, подпрограммы на языке ассемблера и любые приемы, которые ее разработчик может придумать, найти или позаимствовать у других. Наконец, такие программы должны разрабатываться в процессе правильно ор¬ ганизованной работы, а не когда сидящего за дисплеем про¬ граммиста заполночь охватывает вдохновение. Но самое главное в серьезной программе то, что ее автор имеет серьезные намерения: желание решить полезную задачу профессиональным образом. Если такое намерение у вас есть, то вы обязательно обнаружите, что для создания такой программы одного желания недостаточно. Требуются некоторые знания и определенная квалификация. Часть программистов приобретает необходимую квалификацию с опытом, но, к сожа¬ лению, многие так и не осваивают необходимые приемы. Все, что излагается в этой книге, относится к семейству пер¬ сональных компьютеров фирмы IBM: IBM PC, PC XT, PC AT и PCjr2, а также к большинству совместимых с ними машин. Предлагаемые концепции проектирования программ применимы практически к любой вычислительной системе. Примеры програм¬ мных текстов рассчитаны на интерпретатор BASICA для ПК фирмы IBM и версии 2.1. DOS. Операционная система DOS 2.1 и интерпретатор BASICA той же версии используются во всех ма¬ шинах этой фирмы кроме PC/AT, которая поставляется с версией DOS 3.0 и интерпретатором BASICA 3.0, являющимися соответственно расширением DOS 2.1 и интерпретатора BASICA 2.1. Вследствие этого примеры на Бейсике, применяющие DOS, будут работать на всех машинах упомянутой фирмы. Этими при¬ мерами смогут воспользоваться (возможно, лишь с незначитель¬ ными модификациями) и программисты, имеющие совместимые с ПК фирмы IBM компьютеры, которые работают с очень близ¬ кими версиями DOS и языком Бейсик фирмы Microsoft. 1 Определение термина «сопровождение» см. на с. 27. — Примеч. пер. Названия этих ПЭВМ переводятся соответственно так: ПК фирмы IBM, усовершенствованный ПК, передовой ПК и младший ПК.—Примеч. пер. 11
Эта книга' представляет попытку поделиться с вами тем, чему я научился в отношении разработки программ, и тем, что я знаю о ПК IBM и о совместимых с ними машинах. В книге содержится много общих указаний, конкретных примеров, под¬ программ, фрагментов программ и всего, что я мог придумать, чтобы донести свои мысли до читателя. Я собрал эту информацию по многочисленным книгам и журнальным статьям, в тайниках умов экспертов по ПК IBM, а также в процессе проектирования, разработки и оценки программ для различных микрокомпьютеров, чем я занимался в течение ряда лет. Надеюсь, что часть моего опыта может пригодиться и вам.
Введение Эта книга предназначена тем, кто желает с максимальной эф¬ фективностью использовать персональные компьютеры фирмы IBM и совместимые с ними ПЭВМ. Хотя в книге говорится только об этих компьютерах, основная масса содержащегося в ней мате¬ риала может пригодиться при разработке программ для любой ЭВМ. Через всю книгу последовательно проводятся четыре темы. Первая тема: разрабатываемые программы должны быть друже- ствены пользователю. Для этого вам следует понимать своих поль¬ зователей. При проектировании и разработке программ вы дол¬ жны сознательно учитывать их потребности. В книге показывает¬ ся, как это делать. Вторая тема: программа должна быть дружествена программи¬ сту. Это значит, что она должна быть логично организована, легко читаема, хорошо документирована и пригодна для сопровождения. Для этого вам придется приложить дополнительные усилия и выпо¬ лнить определенные требования. Но эта работа не напрасна: в противном случае через несколько месяцев ваша программа прев¬ ратится в загадку даже для вас самих и тем более не будет понятна другим программистам. Третья тема: приемы управления ПК. Вы должны уметь заста¬ вить ПК делать все, что вам надо. Если, скажем, вам понадобится сформировать меню или прочесть текстовый файл, то вы должны иметь возможность это сделать. Задача распадается на две части. Во-первых, программное обеспечение компьютера — DOS и язык Бейсик должны это позволять. Во-вторых, вы сами должны знать, какие действия нужны для выполнения работ: какие строки про¬ граммного текста надо набирать, какие кнопки нажимать и т. п. Как ПК фирмы IBM, так и его DOS и Бейсик установили стандарт, на который равняется отрасль. Это мощные системы, предоста¬ вляющие такие возможности, каких нет у большинства других микрокомпьютеров. Но чтобы реализовать их потенциал, вам придется изучить и освоить ряд приемов. К сожалению, одна учеба не сделает вас хорошим программистом — ведь вы не заговорите свободно на суахили, выучив наизусть суахили-русский словарь. Чтобы овладеть языком, недоста¬ 13
точно знать значение каждой лингвистической единицы. Нужны некоторые идеи — большие и малые. Большие идеи — это филосо¬ фия и общие подходы к проектированию программ. Малые идеи — это приемы программирования: проверенные способы решения некоторых задач, таких, например, как формирование меню или чтение текстового файла. В книге содержатся примеры идей того и другого рода. Четвертая тема: программы должны разрабатываться органи¬ зованно и согласно определенной стратегии. Тема инженерного программирования не вызывает особого восторга у большинст¬ ва людей, поэтому я постараюсь не слишком надоедать вам ею. Но существует ряд важных концепций, которые заслуживают внимания. Перечислим их: это техникапрограммирования«сверху вниз», построение программ из модулей (крупных блоков) и систе¬ матическое тестирование и анализ программ. Вначале эти концеп¬ ции выглядят абстрактно, но когда вы их освоите, они смогут су¬ щественно повлиять на ваш стиль проектирования и разработки программ. В результате ваши программы станут проще, понятнее и будут содержать меньше ошибок. Легко увидеть, что из перечисленных четырех тем непосред¬ ственно к ПК относится только третья. Остальные приложимы к любой вычислительной системе. Данная книга будет частично по¬ священа программированию для ПК, частично — человеческо¬ му фактору, частично — инженерному проектированию и части¬ чно — системной и эксплуатационной документации (документа¬ ции пользователя). Любой читатель найдет в этой книге что-то полезное для себя. Для кого написана эта книга? Краткий ответ — для людей, которые желают, чтобы разрабатываемые ими для ПК программы стали лучше. Более полный ответ — для людей, которые уже в какой-то мере умеют программировать на ПК, хотят разрабаты¬ вать для него серьезные прикладные программы и должны повы¬ сить свою квалификацию в этой области. Книга предполагает зна¬ комство с ПК, языком Бейсик и DOS. В ней не будут объясняться элементарные вещи типа того, как подключать к компьютеру дисковод или что такое цикл FOR/NEXT. Предполагается, что это вы знаете. Иначе говоря, эта книга не для начинающих прог¬ раммистов. Добрый им совет — отложить ее и освоить азы прог¬ раммирования. Хотя для чтения настоящей книги не обязательно быть специалистом по программированию, основы его знать не¬ обходимо. Но, впрочем, если вы сомневаетесь в своей подготовке, то постарайтесь эту книгу прочесть. Я приложил большие усилия, чтобы все полностью объяснить, и проиллюстрировал каждое утверждение примерами, которые помогут вам во всем разобраться. Книга написана в расчете на читателя, имеющего в своем рас¬ поряжении систему, состоящую из ПК с монохромным или цветным 14
монитором, позволяющим отображать 80 столбцов текста, а так¬ же укомплектованную принтером и по крайней мере одним дис¬ ководом. Предполагается наличие операционной системы DOS 2.1, обеспечивающей доступ к расширенному языку Бейсик фирмы IBM. Но если ваше оборудование или программное обеспечение не вполне соответствует этим условиям, то не отчаивайтесь. Вы увидите, что основная часть программ будет прекрасно выпол¬ няться и на вашей системе, хотя, возможно, вам придется внести в них отдельные мелкие изменения. Для большинства примеров несущественно, имеется ли у вас монохромный или цветной мони¬ тор, допускает ли он вывод 40 или 80 столбцов и есть ли у вас один или два дисковода (однако один дисковод иметь необходимо). О выводе на печать в книге говорится совсем мало, но каждому серьезному программисту принтер нужен. Набросав в общих чертах содержание книги, будет, пожалуй, неплохо сказать и о том, что в ней обойдено молчанием. Прежде всего я мало что сказал о цвете, по крайней мере, в том значении, в котором он используется в игровых и развлекательных програм¬ мах. Говорится только об использовании цвета для передачи ин¬ формации и о том, какие сочетания цветов для этого хороши и нап¬ ротив, плохи. Другими словами, я сосредоточил внимание на, так сказать, практическом значении цвета, а не на цвете как таковом. Кроме того, я мало что сообщаю и о графике. Это сложная тема, и, откровенно говоря, я предпочел бы ее не касаться. Сущест¬ вуют книги, написанные на эту тему, и было бы несложно написать еще одну: о графике для ПК. Эту задачу я оставляю другим. В книге мало говорится и о звуке. ПК обладает богатыми воз¬ можностями выдачи различных звуков, и эта возможность исполь¬ зуется в играх, развлекательных программах и при сочинении му¬ зыки. К сожалению, в большинстве программ обработки деловой информации, которым посвящена настоящая книга, «таланты» ПК в данной области особого значения не имеют. Эту тему я так¬ же оставляю другим авторам. Теперь вы знаете, что в данной книге опущено. Я придерживаюсь следующего подхода к представлению ин¬ формации: каждое положение сопровождается примером, который вы можете ввести в свой компьютер. Большинство глав книги вклю¬ чает несколько текстов на Бейсике (фрагментов программ, под¬ программ и коротких программ), которые вы можете опробовать сами. Рекомендую вам этим не пренебрегать. Тогда вы не только больше узнаете, но и сама учеба будет интереснее и приятнее. Если, к тому же, вы сохраните подпрограммы на диске, то к концу работы над книгой у вас останется библиотека, очень полезная для разра¬ ботки ваших собственных программ. Когда я писал эту книгу, то старался следовать правилу «чем меньше, тем лучше». Знаю по собственному опыту, что при обучении программированию основная сложность чаще всего зак¬ лючается в том, чтобы разобраться: какие сведения будут в даль¬ 15
нейшем нужны, а без каких можно спокойно обойтись. К сожале¬ нию, судить об этом я смог только тогда, когда выучил (попытал¬ ся выучить) все, затем я отбросил примерно 90% из всего того, чем я с таким трудом овладел. Эта книга построена по-другому. Вместо того, чтобы предла¬ гать вам на выбор несколько методов центрирования строки символов на экране монитора, создания файла данных, проекти¬ рования меню и т. п., я сообщаю вам один простой, естественный, хорошо работающий способ решения проблемы. Надеюсь, это облегчит дело, поскольку у вас будет меньше трудностей и лишней работы. Книга состоит из десяти глав и трех приложений. Главы 1 — 3 вводные, в них рассказывается о том, чем вам следует овладеть, прежде чем сесть писать свои программы. В главе 1 описывается методика составления программ, дружественных пользователю и программисту. Сообщаются некоторые приемы программирования и дается набросок общей стратегии разработки программ. В гла¬ ве 2 рекомендуются оборудование, программное обеспечение и литература, которые следует приобрести перед тем, как начать работу над серьезным проектом. Главы 4 — 8 посвящены различ¬ ным вопросам программирования. В них предлагаются такие методы решения типовых задач, которые позволяют создать дру¬ жественную пользователю программу. В главе 9 мы знакомимся с Фредом — начинающим програм¬ мистом, странствующим по свету в поисках более или менее абсо¬ лютной истины о системной документации, и повествуем о том, чему он научился от Великого Гуру программирования. Приклю¬ чения Фреда продолжаются в главе 10, рассказывающей о том, что он узнал о руководствах пользователя и хелп-кадрах1. В приложениях приводятся сведения, которые могут оказаться полезными как при чтении данной книги, так и в дальнейшей ра¬ боте. В приложении А приводятся коды ошибок и соответствующие сообщения Бейсика, в приложении В — шифры символов в коде ASCII2 и соответствующие им значения функции CHR$, а в при¬ ложении С — зарезервированные слова Бейсика. Как следует читать эту книгу? Рекомендую начать с главы 1 и читать до конца, пытаясь попутно выполнять на ПК описанные в каждой главе действия. В дальнейшем вам, возможно, захо¬ чется вернуться к главам 4—8, содержащим основную справочную информацию. 1 Хелп-кадрами называют выдаваемые программой пользователю на экран кадры с инструктивной информацией о возможностях и способах управления программой. В хорошо спроектированных программах такая информация не мешает работать и в то же время облегчает освоение программы.—Примеч. пер. ~ ASCII — американский стандартный код для обмена информацией.—Примеч. пер. 16
Глава 1 КАК ПРИ ПРОЕКТИРОВАНИИ ПРОГРАММ УЧИТЫВАТЬ ИНТЕРЕСЫ ПОЛЬЗОВАТЕЛЯ В данной главе вводятся четыре основные темы данной книги: как сделать программу дружественной пользователю, как сделать ее дружественной программисту, как обеспечить управление ПК и как разрабатывать программы по плану. В главе объясняется смысл этих тем, их значение и дела¬ ется попытка добиться от вас более осознанного к ним отношения. Эти четыре темы проходят красной нитью через всю книгу. Насколько важны идеи, лежащие в основе этих тем? Это за¬ висит от ваших целей. Если программа, которую вы пишете, нужна только вам, то, наверное, вас не будет заботить, насколько дружественной вы ее сделаете самому себе в качестве пользователя и программиста. Однако, вас, наверное, все же будет интересовать, как обеспе¬ чить управление компьютером и как улучшить стратегию разработ¬ ки программы. С другой стороны, если вы работаете совместно с другими программистами, скажем, над большим проектом, то обеспечение дружественности программы как пользователям, так и програм¬ мистам будет важным моментом ее разработки. В книге предлагается методика, позволяющая вам стать более хорошим программистом, причем общие черты этой методики изла¬ гаются в данной главе. Проработав эту главу, вы овладеете основ¬ ными положениями проектирования программ, ориентированных на пользователя. КАК СДЕЛАТЬ ПРОГРАММУ ДРУЖЕСТВЕННОЙ пользователю В эти дни много говорят о дружественности пользо¬ вателю, хотя никто еще не дал этому понятию удовлетворитель¬ ного определения. В общем, дружественность — это нечто хоро¬ шее, как хлеб и отчий дом, и так к ней относятся даже те, кто о дружественности имеет самые смутные представления. Полу¬ чается удобное для рекламы сочетание: не совсем ясно, что это, но вещь хорошая. 17
«Дружественность!» звучит как политический лозунг. Пред¬ ставьте ярко освещенный зал, развевающиеся знамена и стоящего на трибуне перед большой аудиторией политика, провозглашаю¬ щего нечто в таком роде: «В прошлом наш народ уделял слишком мало внимания пользо¬ вателю программ! Мы не были дружествены пользователю! Мы не выполняли своих обещаний! Наше правительство будет следить, чтобы пользователь получал все, на что он имеет право. Мы назначим компетентную комиссию, которая займет¬ ся расследованием совершавшихся против пользователей зло¬ употреблений и подготовкой рекомендаций по их устранению. Мы будем действовать честно и обдуманно. Наша цель — пол¬ ностью искоренить злоупотребления против пользователей еще при жизни нынешнего поколения». Пожалуй, такое звучит фантастично, но не в большей мере, чем типичная реклама дружественной пользователю программы. Вы, наверное, сталкивались с чем-то подобным. Вы встречали реклам¬ ные объявления, утверждавшие, что некоторая программа пред¬ ставляет образец дружественности пользователю потому, что она использует «мышь», может быть освоена за пять минут и с ней может работать восьмилетний ребенок. Что общего с реальностью имеют подобные утверждения? Рассмотрим понятие дружественности пользователю.Было ли оно вообще когда-нибудь адекватно определено? Многие имеют самые различные, несвязные, а иногда и странные представ¬ ления об этом понятии. Некий программист считает, что дру¬ жественность пользователю предполагает необходимость защиты от всех ошибок, возможных при вводе данных. Для этого про¬ граммист заставляет компьютер всякий раз, когда пользователь наберет данные и нажмет клавишу «Ввод», выдавать на экран такой вопрос: Вы уверены? (д/н): Когда пользователь наберет «д», появляется такое сообщение: Вы действительно совершенно уверены? (д/н): Когда пользователь совершает ошибку, такое предостережение может оказаться полезным, но после того, как он освоит ввод данных, оно будет только вызывать раздражение. Другой программист полагает, что дружественность пользо¬ вателю равнозначна использованию меню. Он верит, что меню сами по себе делают программу дружественной. В этом есть элемент истины, как, впрочем, и в том, что пользователь должен быть защищен от ошибки ввода, но оба представления оказываются чрезмерными упрощениями смысла дружественности пользователю. Любитель меню старается применять их всюду, даже там, где это и ненужно, и нежелательно. В некоторых 18
случаях меню могут быть полезны, но они могут и замедлить работу, особенно работу опытных пользователей. Мания меню чаще всего вредит работе. Третий программист увлечен цветом. Он пользуется им в каж¬ дом кадре выдачи. В результате программа радует глаз, хотя временами используемые цветовые сочетания создают зритель¬ ные иллюзии, а контрасты затрудняют чтение. Ну что же, и цвет может быть полезен, но правильно им пользоваться трудно: для этого требуется иметь определенные знания о восприятии цвета. Еще один программист увлечен графикой, другой — пикто¬ граммами, третий — «окнами»... Можно было бы продолжить этот список и далее, но вместо перечисления ошибок и недо¬ пониманий лучше представить картину действительного смысла понятия дружественности пользователю. НАЧИНАЙТЕ С ПОЛЬЗОВАТЕЛЯ При проектировании любого объекта, которым будут пользо¬ ваться люди, желательно возможно больше узнать о будущих пользователях. Тогда вы сможете выполнить проект так, чтобы удовлетворить их потребности. Во многих случаях вы так и по¬ ступаете, часто неосознанно. Разговаривая с маленьким ребенком, вы употребляете простые слова и короткие предложения, делаете паузы, чтобы убедиться в том, что он вас понимает. Когда вы жарите мясо, то спраши¬ ваете гостей, какое мясо они предпочитают: хорошо или средне прожаренное или же с кровью и стараетесь угодить их вкусам. Если ваши кулинарные способности близки к моим, то бифштекс не всегда получается «дружественным пользователю», но по край¬ ней мере вы стремитесь к этому. Когда вы пишете научную статью для журнала, то пользу¬ етесь соответствующей профессиональной терминологией и не ого¬ вариваете многих вещей, которые читатели-специалисты должны знать. Вероятно, ваша статья окажется непонятной непосвящен¬ ным, но аудитория, на которую вы рассчитываете, не должна испытывать трудностей. Когда вы пишете письмо своему богатому и нетерпимому дядюшке Оскару, то избегаете сильных выражений, благожела¬ тельных отзывов о либералах и т. д., так как по собственному опыту знаете, что он обостренно относится к подобным вопросам и может вычеркнуть вас из своего завещания. Все это примеры того, как в своей повседневной жизни вы учитываете специфику лиц, с которыми общаетесь. Как мы уже отмечали, хотя большей частью это делается неосознанно, иногда вы так поступаете вполне сознательно. Например, когда вы пишете дядюшке Оскару, то, вполне возможно, держите в уме 19
список контрольных вопросов, с помощью которых осуществля¬ ете цензуру своего письма. С маленьким ребенком вы разго¬ вариваете не столь внимательно и едва ли при этом специаль¬ но размышляете о том, что делаете. Сознательно или нет, но во всех случаях вы признаете, что ваша аудитория имеет опре¬ деленные потребности и что предоставляемую вами информацию вы должны организовать так, чтобы эти потребности удовлет¬ ворить. Написать дружественную программу труднее, чем дружествен¬ ное письмо. Эта работа может оказаться несколько необычной для вас. С чего ее начать?— С пользователя. Определите своего поль¬ зователя с максимально возможной точностью. Задайте себе такие вопросы: • насколько квалифицирован пользователь в области вычис¬ лительной техники? • в какой мере пользователь понимает, как работают про¬ граммы ЭВМ? • насколько он владеет теорией, на которой основана ваша программа (если, скажем, вы пишете программу бухгалтер¬ ского учета, то требуется уяснить, насколько квалифици¬ рован пользователь в области бухгалтерии)? • насколько умен пользователь? • нет ли у него каких-нибудь физических недостатков или особенностей (например, дальтонизма), влияющих на ис¬ пользование им программы. Этот список вопросов ни в коей мере не полон, но он дает представление о том, какого рода вопросы надо поставить перед началом проектирования программы. Выяснив, кто будет вашим пользователем, вы сможете определить его потребности и спроектировать программу так, чтобы эти потребности удов¬ летворить. Если, например, программой будут пользоваться дети или не разбирающиеся в вычислительной технике взрослые, то для того, чтобы им легко было ее освоить, вам следует обеспечить в программе много выдаваемых на экран подсказок. Если вы имеете дело с квалифицированными взрослыми, то можно меньше заботиться о том, как им помочь, а больше внимания уделить тому, как сделать свою программу быстрой и эффективной. Если программой будут пользоваться в основном мужчины, то выдава¬ емое на экран изображение следует проектировать так, чтобы от пользователей не требовалось различать цвета, поскольку около 10 % мужчин страдают дальтонизмом. Именно это я и имел в виду, говоря об учете интересов пользователя. Делать это нетрудно, но для многих программис¬ тов такая работа непривычна. Программисты часто не задумы¬ ваются о пользователях. Они проектируют программы для самих 20
себя, будто бы все обладают их квалификацией и умственными способностями. При этом они проявляют примерно такое же внимание к пользователю, как при попытке объяснить малень¬ кому ребенку макроэкономическую теорию. Программисту надо лучше разбираться в жизни. КРИВАЯ ОБУЧЕНИЯ ПОЛЬЗОВАТЕЛЯ По мере того как люди приобретают опыт и квалификацию в некоторой области, с ними происходят любопытные вещи. Имея практику и хорошего учителя, они начинают со. временем работать быстрее и точнее. Действия, некогда требовавшие тща¬ тельного обдумывания и осторожных движений, становятся быст¬ рыми и автоматическими. Решения принимаются быстро и, каза¬ лось бы, без особых раздумий. Все мы наблюдали, как это происходит и с нами, и с другими. В этом нет ничего таинственного. Зависимость производительности труда от опыта называют иногда кривой обучения пользователя. Этот термин появился в исследованиях по экспериментальной психологии, в которых строят кривые зависимости различных мер производительности, например точности или скорости, от опытно¬ сти (рис. 1.1). Форма этой кривой примерно одинакова для задач различного рода, так что можно считать, что она описывает освоение большинства видов деятельности. Форма кривой интер¬ претируется крайне просто: по мере роста квалификации люди начинают работать быстрее и совершают меньше ошибок. Порой рост производи¬ тельности просто удивляет. Пусть вы проектируете прос¬ тую программу, скажем, для вычисления размера ежеме¬ сячного взноса при пога¬ шении ссуды. Вначале поль¬ зователь работает с этой программой медленно, но когда он полностью ее ос¬ воит, скорость возрастает в несколько раз. Чем сложнее программа, тем дольше ее осваивает пользователь и тем более пологой будет кри¬ вая обучения. Некоторые программы настолько слож¬ ны, что пользователи и не пытаются освоить их пол¬ ностью, а работают только с интересующей их частью. Рис. 1.1. Кривая обучения пользовате¬ ля. По мере того как пользователь приобретает опыт и квалификацию, растет производительность его труда. На данном рисунке изображена эта за¬ висимость (типичный случай). Быстрее всего производительность растет в на¬ чале обучения 21
В таких случаях кривая их обучения так никогда и не стано¬ вится плоской. Как правило, полностью освоив программу, пользователь рабо¬ тает с нею иначе, чем раньше. На первых шагах делается много проб и ошибок, проявляется много озабоченности и осто¬ рожности. В дальнейшем неуверенность и осторожность проходят, а пользователь требует от программы скорости. Помогавшие но¬ вичку возможности типа обязательных хелп-кадров превраща¬ ются в препятствия, тормозящие работу. Некоторые пользователи начинают оценивать программу хуже, чем оценивали ее сначала, забывая, как выдаваемые ею инструкции помогли приобрести им нынешний уровень квалификации. Следовательно, вы не можете спроектировать программу, удовлетворительную даже для одного пользователя, поскольку сам пользователь будет меняться. Это ставит вас в сложное положение. Если, стремясь создать условия для быстрого освоения программы, вы проектируете ее с большим числом подсказок и хелп-кадров, то в некоторый момент пользователь перерастает эту программу и начинает нахо¬ дить ее несколько нудной. Если же вы выбираете противополож¬ ный подход и оказываете совсем мало помощи пользователю, почти не выдавая на экран инструкций, то освоить такую про¬ грамму будет труднее. Короче, программисту приходится делать выбор между легкостью освоения и удобством работы. В некоторых случаях разумно предпочесть легкость освоения программы, в других — удобство работы. Но лучше всего обес¬ печить в программе возможность и того и другого. Этого можно добиться разными способами. Один из них — подготовить хелп- кадры, но выдачу их на экран сделать необязательной. Другой способ — позволить пользователю выбирать режим работы либо через меню (для новичков), либо набором кода (для опытных пользователей). Существуют и другие способы учета кривой обучения. Они будут обсуждаться подробнее в гл. 6. На настоящий момент вам достаточно осознать, что в процессе работы с программой пользователи учатся и их квалификация растет и что при про¬ ектировании программ вам следует учитывать изменяющиеся по¬ требности пользователей. ЧТО СЛЕДУЕТ ОЖИДАТЬ ОТ ПОЛЬЗОВАТЕЛЕЙ! Каждый программист знает множество историй о глупых, нелепых, а иногда и просто катастрофических случаях, проис¬ ходивших при работе на ЭВМ. Например, программисту звонит пользователь и сообщает, что он следовал руководству буквально шаг за шагом, но не смог добиться, чтобы программа начала работу. После долгой беседы программисту, наконец, приходит в голову, что пользователь не нажимал клавишу «Ввод» после 22
набора входных данных. На вопрос, почему он не делад этого, незадачливый пользователь отвечает, что в руководстве об этом ничего не было сказано. Однажды мне позвонил пользователь, озабоченный тем, что слишком долго идет сжатие файла. Эта процедура обычно зани¬ мает несколько минут. Я спросил, сколько времени его программа пытается выполнить сжатие, и получил ответ: «Примерно два дня». И после этого пользователь еще спрашивал, не слишком ли это долго. Видели ли вы, как кто-нибудь пачкал дискету майонезом, скла¬ дывал ее пополам или засовывал в дисковод боковой стороной? Все это и многое другое случалось в жизни» Не сомневаюсь, что вы можете рассказать истории и похуже. Вывод: ничего не ожи¬ дайте от пользователей. Не вините пользователей, не их дело знать что-либо о компью¬ терах или о вашей программе. Но ваш долг как программиста сообщить пользователям те минимальные сведения, которые им необходимы. И прежде всего сделайте так, чтобы они не страдали от собственной некомпетентности. После того как вы признаете эти положения (а большинство опытных программистов их рано или поздно признают), вы измените свой подход к проектированию программы. Вы пой¬ мете, сколь важно проверять входные данные пользователя на от¬ сутствие ошибок. Вы будете беспокоиться о том, что случится с вашей программой, если пользователь нажмет не вовремя не на ту клавишу, например нажмет комбинацию клавиш Ctrl-Break во время работы с программой. Тогда вы предпримете шаги, предупреждающие возможную катастрофу. Уважайте своих пользователей и защищайте их. Считайте, что они все будут делать неправильно. Для надежности думайте, что они специально вас преследуют и ищут способ заставить вашу программу прекратить работу или сделать что-либо невер¬ но. При проектировании программы не мешает быть немного пара¬ ноиком. Вам станет ясно, были ли вы параноиком в доста¬ точной степени, только тогда, когда с программой поработают пользователи. ДРУГИЕ СПОСОБЫ УЧЕТА ИНТЕРЕСОВ ПОЛЬЗОВАТЕЛЯ Взаимодействие пользователя с компьютером можно считать своеобразным разговором. Пользователь, обычно с помощью клавиатуры, осуществляет ввод. Вводиться могут и данные, и управляющие работой компьютера команды. Со своей стороны, компьютер с помощью дисплея поддерживает разговор с поль¬ зователем, Другими словами, пользователь общается с компью¬ тером, набирая команду, компьютер обрабатывает эту команду, а затем отвечает, выдавая что-то на экран дисплея или прин¬ 23
тер. Основная идея разговора между поль¬ зователем и компью¬ тером изображена на рис. 1.2. Первый элемент диалога — ввод. Его можно осуществлять с помощью клавиатуры или другого внешнего устройства, например ручки управления, све¬ тового пера, «мыши» или устройства голо¬ сового ввода. Вводом называется то, что про¬ исходит, когда поль¬ зователь вводит инфор¬ мацию в компьютер. Как уже отмечалось, пользователи несовер¬ шенны и будут делать ошибки. Поэтому прог¬ рамма должна отфиль¬ тровывать вводимые данные и принимать только допусти м ые сообщения. Это дела¬ Рис. 1.2. Диалог между пользователем и компьютером. Взаимодействие между поль¬ зователем и компьютером можно сравнить с разговором, который со стороны пользо¬ вателя осуществляется посредством ввода данных, обычно с клавиатуры, а со стороны компьютера—посредством вывода, обычно на экран дисплея ется с помощью их проверки на ошибки. Итак, для очистки ввода вам следует спроектировать различные фильтры или, иначе говоря, проверки на ошибки. Второй элемент разговора — вывод, т. е. ответ, который дает компьютер. В большинстве случаев вывод осуществляется на эк¬ ран дисплея. Конечно, вывод может осуществляться и по-другому, например на принтер, динамик или схемы управления моторами и другими механизмами. При любом виде выдачи необходимо добиться, чтобы она была ясна и понятна пользователю. Он дол¬ жен иметь возможность эту выдачу эффективно использовать. Существуют правильные и неправильные способы проектирования выдачи и вам следует знать разницу между ними. К счастью, существует немало действенных правил проектирования выдачи на экран и на печать. Диалог между пользователем и компьютером происходит также и при управлении программой. Этим термином называют взаимо¬ действие пользователя с компьютером с целью заставить про¬ грамму что-то сделать. Например, один из наиболее распро- 24
Рис. 1.3. Подобные меню часто используются для того, чтобы дать пользователю возможность управлять работой программы. Из перечисленных в меню вариантов пользователь выбирает желаемый, после чего программа выполняет соответствующую функцию страненных методов управления — с помощью меню. В програм¬ мах, использующих этот метод, пользователь выбирает один из представленных в меню вариантов и указывает его с помощью клавиатуры или другого устройства, например светового пера. Затем компьютер выполняет указанную пользователем программу (рис. 1.3). Выбор с помощью меню — лишь один из многих методов управления программой. Как и все методы управления, он имеет свои достоинства и слабые стороны. Программист должен знать различные методы управления, их преимущества и недостат¬ ки как с точки зрения пользователя, так и с точки , зрения эффективности программы. Многие считают, что все программы для микрокомпьютера обязательно должны использовать меню. Это неверно, меню — только одна из многих доступных нам возможностей. Существуют дружественные и недружественные способы про¬ ектирования ввода, вывода и управления программой. При проек¬ тировании бывает трудно отделить кодирование программы от обеспечения ее дружественности. Поэтому вам следует сначала овладеть правилами, обеспечивающими дружественность, а затем следовать им при кодировании. Эти правила приведены в гл. 4, 5 и 6. 25
ОТЛАДКА ПРОГРАММ Программа с ошибками всегда недружественна. Если при не¬ которых условиях программа прекращает работу, теряет данные, выдает на экран абракадабру и вообще делает то, чего не сле¬ дует, то она еще не готова к использованию. Поступающая пользователю программа должна быть безупречной и свободной от ошибок. Часто говорят о двух стилях разработки программ. При быст¬ ром стиле программу лепят кое-как, на скорую руку, а затем отлаживают. Неторопливый стиль имеет то преимущество, что он позволяет избежать многих ошибок с самого начала. Он требует большого труда на начальных этапах работы, когда производится планирование программы, но в целом объем работы уменьша¬ ется. Такая стратегия разработки программ описывается в данной главе, подробнее она рассматривается в гл. 4—8. ЭКСПЛУАТАЦИОННАЯ ДОКУМЕНТАЦИЯ Эксплуатационная документация (документация пользова¬ теля) — это документация, рассказывающая пользователю о про¬ грамме. Она может быть представлена в форме руководства пользователя, хелп-кадров или в другом виде, используемом в самой программе, а также в виде их сочетания. Программисту, имеющему опыт работы с микрокомпьютерами, должно быть известно, что значительная часть поставляемой с программами документации совершенно неудовлетворительна. Часто она неполна, вводит в заблуждение, неточна или обладает одновременно всеми этими недостатками. К тому же значитель¬ ная часть документации пользователя плохо организована и даже просто плохо оформлена. Сколько у вас программ, документа¬ ция на которые представляет собой неразборчивые ксерокопии, прихваченные в уголке скрепкой? Если вас раздражают грам¬ матические и орфографические ошибки, то вы, наверное, удивля¬ етесь: кого только фирмы-издатели программ нанимают для сос¬ тавления руководств. Существуют хорошие и плохие способы подготовки докумен¬ тации пользователя; плохих способов больше, чем хороших. Но не отчаивайтесь. Есть методы, позволяющие определить, какое соче¬ тание сопроводительной и содержащейся в самой программе документации следует подготовить для ваших программ. Можно подготовить общую схему, объясняющую, что должно содер¬ жаться в руководстве пользователя. Следуя всего нескольким простым правилам, вы сможете получить адекватный, если не образцовый, комплект документации. Несомненно, можно рабо¬ тать лучше, чем многие издатели программ. 26
Значение документации пользователя зависит от того, кто будет пользоваться программой. Если она предназначена только для вас, то она не особенно нужна, поскольку вы и так хорошо в ней ориентируетесь. Но если с программой будут работать и другие люди, то значение документации пользователя чрезвычайно велико. Как бы ни была ваша программа хороша сама по себе, без адекватной документации, позволяющей объяснить ее другим, она подобна приземлившемуся на вашем дворе чужому межпланетному кораб¬ лю. Представьте, что вы открыли люк, зашли внутрь, увидели полупрозрачные рычаги, вспыхивающие табло и услышали стран¬ ное постукивание. Вы решили слетать на нем в центр, пере¬ кусить. Но как взлететь? Как провести корабль к цели? И как благо¬ получно приземлиться? Хорошо, если инопланетяне оставили вам руководство пользователя (желательно на русском языке и с большим числом хороших иллюстраций) или маленький экран, под которым написано: «Нажми, когда потребуется помощь». Требования к руководству пользователя подробнее рассматри¬ ваются в гл. 10. (Не знаю, помогут ли они вам готовить документацию на космические корабли.) КАК СДЕЛАТЬ ПРОГРАММУ ДРУЖЕСТВЕННОЙ ПРОГРАММИСТУ Программистов обычно заботит отладка программ, их сопро¬ вождение (т. е. незначительная модификация или внесение изме¬ нений по требованиям отдельных пользователей), а иногда и коренная переработка или разработка совершенно новых про¬ грамм на основе существующих. Сложность этой работы опреде¬ ляется рядом факторов. Один из этих факторов — размер программы. Если программа невелика, то разобраться в том, что она делает, отладить и улучшить ее обычно бывает несложно. Однако с ростом про¬ граммы в какой-то момент становится слишком сложно охватить ее мысленно. Формального метода, позволяющего определить границы, когда достигается эта точка, не существует, но опытные программисты хорошо ее чувствуют. Каждый, кто разрабатывал программу на Бейсике длиною более чем, скажем, 50 строк, знает, как трудно бывает распутать, что делает каждая строка. Вторым фактором, влияющим на понимание программы про¬ граммистом, является то, как она спроектирована, т. е. каким принципам следовал разработчик, если он вообще сле¬ довал каким-нибудь принципам. Например, программу, разбитую на модули, которые обозначены в тексте примечаниями (REM), 27
обычно бывает проще понять, чем монолитный текст без ком¬ ментариев. Если вы убеждены в необходимости дружественности про¬ граммы другим программистам, то вы должны добиться, чтобы она стала понятной. Конечно, случается и так, что кроме вас никто и никогда не увидит текст вашей программы. Стоит ли в таком случае заботиться о ее дружественности? Если у вас абсолютная память, то нет. Но большинство из нас страдает несовершенством памяти, а значит, имеет смысл проектировать свои программы так, будто бы их потребуется разбирать другим программистам. Третий фактор, от которого зависит дружественность вашей программы программистам,— качество ее документации. Доку¬ ментация, написанная программистом для пояснения работы про¬ граммы, называется системной документацией. Она состоит из при¬ мечаний в тексте программы и различных письменных документов: описаний подпрограмм с разъяснениями их работы, таблиц функ¬ ций, массивов и переменных; описаний файлов с форматами записи и т. п. Вся эта документация предназначена для того, чтобы объяснить работу программы настолько детально, чтобы другой программист мог разс^браться в ее работе. Тогда этот программист сможет исправить ошибку, внести изменение или выполнить другую работу, требующую вмешательства в текст программы. Известно, что без адекватной системной документации про¬ грамма на Бейсике длиною более нескольких строк обычно бывает непонятна другому программисту. Хуже того, со временем она становится непонятна даже самому автору. Мы многое забы¬ ваем, и наше собственное творение может стать для нас загад¬ кой, если оно не было вовремя документировано. Некоторые программисты не видят смысла в подготовке сис¬ темной документации, возможно, они хотят оставить свои про¬ граммы окутанными легкой тайной. Тогда никто другой не сможет эти программы разобрать, изменить, а значит, и заменить такого программиста на работе. Все мы слышали или читали о программисте, который один на всем белом свете знал, как ра¬ ботает определенная программа, и к которому, спустя долгие годы, обращались, чтобы поддержать ее в работоспособном со¬ стоянии. Конечно, в этом не всегда виновен программист, но часто виновен все же именно он. Для тех, кому нравится хранить секреты, пренебрежение системной документацией может служить профессиональным приемом. Но вы то, конечно, выше таких хитростей и способны оценить значение системной документа¬ ции. Вы должны решить, нужна ли вам документация, а если нужна, то в каком объеме. Если вы пишете короткую программу, то часто можете спокойно пренебречь системной документацией. При более длинной программе она вам необходима. 28
В любом случае желательно проектировать программу так, чтобы ее было легко читать. Подход, позволяющий добиться этого, описан в данной книге. В последнем параграфе данной главы разъясняется, как разбивать программу на модули, а в гл. 3 приводится образец такой программы. Последующие главы содержат многочисленные примеры программных моду¬ лей. Назначения и требования к системной документации следует хорошо освоить до того, как приступать к разработке программы. В идеальном случае ее следует писать одновременно с коди¬ рованием программы. Более подробно эта тема разбирается в гл. 9. КАК УПРАВЛЯТЬ КОМПЬЮТЕРОМ Вы сможете управлять компьютером, если овладеете эффек¬ тивными и надежными методами (обычно реализованными с по¬ мощью подпрограмм), позволяющими вам, например: • отображать информацию на экране дисплея или принтере; • принимать вводимые с клавиатуры данные; • выбирать и проектировать методы управления программой; • связывать в цепочку или соединять отдельные программы; • проектировать и использовать файлы на дисках. Ключ ко всему этому — разбиение программы на модули. Модули могут иметь любой размер, но обычно они состоят из нескольких строк. Подпрограммы являются модулями. Некоторые модули содержат несколько подпрограмм, а бывают модули и еще большего размера. Одно из важнейших условий управляемости компьютера — правильное представление о том, что образует программу. Опыт¬ ные программисты думают о программе, как о наборе модулей, а не операторов языка Бейсик. Они обычно не составляют про¬ грамму строка за строкой, а по мере возможности строят ее из модулей, хранящихся в библиотеке модулей и подпрограмм. Это быстрее, легче и эффективнее, чем заниматься построчным кодированием. Разбиение программ на модули разбирается в дан¬ ной главе, более подробно модульное программирование рассма¬ тривается в гл. 3 и 7. Упомянутые выше методы управления компьютером излага¬ ются в гл. 4—8. Чтобы дать вам представление о содержании книги, рассмотрим вкратце содержание этих глав. Каждая из них включает несколько примеров текста на Бейсике, иллюстрирую¬ щих соответствующую тему. В гл. 4 рассматриваются принципы проектирования, планиро¬ вания и содержание выводимой на экран дисплея или на печать информации. Она знакомит вас с техникой управления курсором, стирания части экрана, с форматами и расположением дан¬ 29
ных на экране и с прочими аспектами отображения инфор¬ мации. В гл. 5 сообщается, как управлять процессом приема вводи¬ мых пользователем данных. Этот процесс включает проверку на наличие ошибок, выдачу сообщения об ошибках, а также про¬ верку и редактирование входных данных самим пользователем. В гл. 6 описываются методы управления программой и даются общие рекомендации, позволяющие выбрать один из этих методов, в частности меню или ввод названия режима работы. Там же показывается, как сочетать различные методы управления. Б гл. 7 рассказывается, как создавать программу, состоящую из нескольких модулей, и как связывать эти модули в цепочку. В гл. 8 разъясняется, что надо знать для работы с тексто¬ выми файлами. Рассматриваются планирование файлов, последо¬ вательный и произвольный доступ к ним и разработка подпро¬ грамм ввода-вывода, которые вы сможете использовать в своих программах. Остальные главы книги также важны, хотя и в другом отношении. В гл. 1—3 излагаются предварительные сведения, с ко¬ торыми вам следует ознакомиться до начала проектирования программ. В гл. 9 обсуждается системная документация, а в гл. 10 — документация пользователя. СТРАТЕГИЯ РАЗРАБОТКИ ПРОГРАММ Этот параграф знакомит вас со стратегией разработки про¬ грамм для микрокомпьютеров. Я называю это стратегией, посколь¬ ку она не состоит из жесткой последовательности шагов, а пред¬ ставляет собой некий общий подход. В прошлом специалисты писа¬ ли детальные процедуры разработки программ, но ни одна из них не оказалась удовлетворяющей всех. Программисты обладают различными личными особенностями, способностями и стилем работы. Нельзя стричь всех под одну гребенку. Эта стратегия представляет собой некоторый набор процедур, требований и предостережений. Признаю, что все это похоже на окрошку, а если слишком внимательно всмотреться в любую ее часть, то многое можно оспорить. Но если все это «переварить», то останется своего рода философия разработки программ. Как вы убедитесь, эта философия подчеркивает важность дружественности пользователю и программисту, значе¬ ние планирования, полноты документации и тщательной проверки получившегося программного изделия. Наше изложение лучше всего начать с двух ключевых аспектов философии проекти¬ рования — с проектирования сверху вниз и с модульного про¬ ектирования. 30
ПРОЕКТИРОВАНИЕ СВЕРХУ ВНИЗ Проектирование сверху вниз подобно понятию о красоте: все согласны, что это хорошо, а многие зарабатывают себе на жизнь тем, что пишут о ней, но трудно найти ей простое опре¬ деление. Здесь я буду избегать технических подробностей, а постараюсь дать вам о таком проектировании простое пред¬ ставление, основанное на здравом смысле. Начну с описания двух подходов к проектированию программ, а вы попробуйте от¬ гадать, который из них — пример проектирования сверху вниз. Случай А: программист сидит за своим компьютером и наби¬ рает первую строку текста программы. Затем он набирает вторую, третью строку и так далее, пока не введет весь текст до последней строки. Тогда он запускает программу, чтобы посмо¬ треть, как она работает. Если появляются ошибки, то он их исправляет. И так он работает до тех пор, пока программа его, наконец, не удовлетворит. Случай Б: программистка сидит и пишет план проектиро¬ вания. В первую очередь она решает, в чем состоит цель проекта. Затем она решает, какие функций должна выполнять программа и какие модули требуются для их реализации. После этого она обращается к своей библиотеке подпрограмм и ищет в ней фрагменты старых программ, которые можно ис¬ пользовать. Только после этого она садится за свой компьютер и разрабатывает первый модуль. Она его тестирует, отлаживает и откладывает в сторону. Затем она проектирует, тестирует и отла¬ живает следующий модуль. После этого она проверяет, как этот модуль работает совместно с первым. И так, подготавливая и сое¬ диняя модуль за модулем, она работает, пока не закончит всю программу. Нетрудно догадаться, какой проектировщик использовал метод сверху вниз. Эта была программистка, работающая систематичес¬ ки. Ее подход к программированию отличается следующими осо¬ бенностями: • она начала с определения целей высшего уровня; • затем она разбила программу на модули; • она разрабатывала все модули по отдельности, тщательно их тестируя и отлаживая перед тем, как перейти к сле¬ дующим; • по мере разработки новых модулей она тестировала их интерфейс1 со старыми. При подходе сверху вниз программы разрабатываются и от¬ лаживаются систематически, в логической последовательности 1 Интерфейс — а) взаимодействие между подсистемами; б) способ взаимо¬ действия; в) реализация способа взаимодействия. Термин используется преи¬ мущественно в электронике и программировании. — Примеч. пер. 31
КОНЕЦ Рис. 1.4. Проектирование сверху вниз начинается с определения основных задач программы, затем оп¬ ределяются модули программы и их взаимосвязи (рис. 1.4). Это контрастирует с более произвольным подходом программиста, просто пишущего текст программы. Значение проектирования сверху вниз особенно возрастает с ростом размера и сложности программы. При разработке простой и короткой программы этот подход можно не прини¬ мать во внимание. Но если вы хотите сделать в программе что-либо значительное, то проектирование сверху вниз существен¬ но увеличивает ваши возможности. МОДУЛЬНОЕ ПРОЕКТИРОВАНИЕ Программным модулем называется отрезок текста программы, выполняющий определенную функцию. Подпрограмма является модулем. Существуют модули и более высокого уровня, чем под¬ программа. Часто модуль включает несколько подпрограмм и ре¬ шает сложные задачи, например задачу создания группы фай¬ 32
лов. Следует отметить, что никаких ограничений сверху на размер модуля нет. Модуль отличается от простого отрезка текста программы тем, что он выполняет некоторую сложную функцию. В определен¬ ном смысле программный модуль так же относится к языку программирования, как язык высокого уровня, например Бейсик, относится к машинному языку ЭВМ. В точности так же, как программисты находят более удобным работать на языке высо¬ кого уровня, а не с отдельными битами и байтами, большин¬ ство квалифицированных программистов считает, что с програм¬ мными модулями работать легче, чем с отдельными операторами программ. Конечно, язык Бейсик или DOS игнорировать невоз¬ можно, так как программа в конечном счете состоит из их операторов, но о своей программе лучше думать не как о неко¬ тором числе строк текста, а на более глобальном уровне — как о сочетании модулей. Модульное проектирование начинается с хорошей библиотеки подпрограмм. Одно из достоинств такой библиотеки — то, что она облегчает проектирование новой программы. Можно взять часть старой программы и перенести ее в новую. Хорошая биб¬ лиотека состоит из тщательно проверенных и отлаженных про¬ грамм. Ими можно пользоваться без тестирования, поскольку вы их уже тестировали и знаете, что они работают правильно. Из таких подпрограмм может состоять значительная часть новой программы. При этом ее создание сводится к построению управ¬ ляющей структуры (т. е. вызовов подпрограмм) и проектиро¬ ванию специфичных для данной программы процедур ввода, об¬ работки и отображения данных. Другое преимущество такого подхода заключается в том, что все ваши программы становятся похожими друг на друга. По¬ скольку они в значительной мере построены из одних и тех же модулей, вы можете переключаться с одной программы на дру¬ гую, не теряя времени на переориентацию. Вы лучше понимаете, где скорее всего можно найти неполадку, легче ее находите и исправляете. Такой подход можно критиковать за то, что он неэлегантен: при его использовании каждая новая задача не проектируется с нуля и не ищется наиболее эффективное ее решение. Но этот подход позволяет сконцентрироваться на поиске сходств между старыми и новыми задачами. Затем старые решения исполь¬ зуют для решения новых проблем. Элегантен ли метод проекти¬ рования сверху вниз или нет, но он имеет два явных преиму¬ щества: позволяет быстро разрабатывать программу и сводит к минимуму число ошибок. Конечно, этот метод подходит не для любой программы и не для любого программиста. Но в большинстве случаев и для большинства программистов он очень эффективен. 2 Зак. 1488 33
СТРАТЕГИЯ ПРОЕКТИРОВАНИЯ ПРОГРАММ Теперь, когда вы почувствовали вкус к философии проекти¬ рования, наступила очередь изучить, из каких шагов слагается стратегия проектирования. Эти шаги изображены на рис. 1.5. Напомним, что в этой стратегии нет ничего жесткого, вы можете добавлять или выкидывать некоторые шаги, изменять их порядок, вообще делать все, что сочтете нужным. Но при этом следите за тем, чтобы не пострадали интересы пользователя. Шаг 1. Начинайте с пользователей. Любой проект лучше всего начать с выяснения того, кто будет пользоваться программой. Вы должны сконструировать программу для них, спроектировать выдачу, которую они смогут понять, найти совер¬ шаемые ими типовые ошибки и обеспечить такое управление программой, которым они смогут эффективно пользоваться. Затем вы должны разработать документацию, которая позволит поль¬ зователям извлечь из вашей программы максимум возможного. Узнайте, кто будет вашими пользователями. Не откладывайте это до тех пор, когда программа будет уже написана. Тогда будет слишком поздно или слишком дорого что-либо изменить. Шаг 2. Спланируйте выдачу программы. Прежде чем начнете писать программы, решите, что будет выдаваться на дисплей. Ведь пользователи будут видеть именно выдачу. Поскольку глав¬ ная цель большинства программ — обеспечить с помощью дис¬ плея взаимодействие пользователя с компьютером, программу следует проектировать, отталкиваясь от вида выдачи. Хотя обычно выдачу проектируют на основе уже разработанной программы, это неверно. Не обязательно с самого начала планировать все детали каж¬ дого кадра выдачи, но проектируйте их возможно полнее. При¬ готовьте макет выдачи на бумаге или на экране дисплея и покажите его, если возможно, потенциальным пользователям. Если вы это сделаете, то обойдете на три-четыре шага нес¬ частного программиста, полностью разработавшего программу только затем, чтобы обнаружить, что пользователи ничего не могут понять в выдаче. Шаг 3. Спланируйте процедуры ввода данных. Компьютер будет обращаться к пользователю посредством выдач на экран. Пользователь будет отвечать ему с помощью клавиатуры или другого устройства ввода. Совместно вывод компьютера и ввод пользователя образуют то, что иногда называют интерфейсом между человеком и машиной. Он должен быть полностью спроектирован до начала кодировки программы. Примите решение о том, какие данные следует вводить, а затем спланируйте процедуры ввода: подсказки, сообщения об ошибках и процедуры верификации и редактирования. 34
1. ОПРЕДЕЛИТЬ, КТО БУДЕТ ПОЛЬЗОВАТЕЛЯМИ Рис. 1.5. Стратегия разработки программ сверху вниз. Философия проектирования сверху вниз мо¬ жет быть преобразована в стратегию разработки программ, проиллюстрированную на данном рисун¬ ке. Пользователю уделяется большое внимание на каждом этапе разработки по данной стратегии — на первом шаге определяется, кто будет пользо¬ ваться программой, затем пользователям демон¬ стрируются кадры вывода, с которыми они будут работать, и процедуры ввода данных. На двух по¬ следних этапах разработки (подготовка документа¬ ции пользователя и участие пользователей в тести¬ ровании и оценке качества программы и ее доку¬ ментации) роль пользователя также очень велика Шаг 4. Спланируйте модули программы. Решите, из каких мо¬ дулей будет состоять ваша программа. Начинайте с самого выс¬ шего уровня и двигайтесь вниз. Пример программного модуля высокого уровня — подпрограмма ввода данных, принимающая их от пользователя. 2* 35
Разбивайте каждый .модуль на подмодули, пока не дойдете до уровня подпрограмм. Затем найдите в библиотеке подпрограм¬ мы, которые можно применять в модулях. В общем случае вам потребуются подпрограммы вывода, ввода данных пользователя, управления программой, связи программ между собой, а также подпрограммы работы с файлами. Гл. 4—8 содержат много программ, выполняющих такие функции. Шаг 5. Спланируйте структуры данных и файлы. Спланируйте структуру данных, т. е. то, как вы будете представлять в программе данные с помощью целочисленных, действительных и строковых переменных и массивов. Спланируйте файлы и формат записей. Шаг 6. Выберите метод управления программой. Определите, каким образом пользователь будет с ней общаться при управ¬ лении ее работой. Иначе говоря, решите, будет ли управление осуществляться с помощью меню или как-нибудь иначе. Спро¬ ектируйте меню или другие, используемые для управления кадры выдачи. Шаг 7. Подготовьте системную документацию. Начинайте раз¬ работку системной документации одновременно с планированием программы. Планы деталей программ, например структур данных и форматов записей,— важная часть системной документации. В дальнейшем системную документацию готовьте одновременно с разработкой программы. По мере возможности делайте это параллельно с программированием, а не. в конце работы. Шаг 8. Разработайте программу. Начните с составления ос¬ новного модуля программы. В программе управления базой дан¬ ных основным будет модуль чтения и записи файлов. В программе, широко использующей графику, основным может быть модуль генерации изображения на экране. Найдите модуль, являющий¬ ся центральным в работе вашей программы, и разработайте его. Подготовьте на него системную документацию и начинайте писать следующий логический модуль и соответствующую до¬ кументацию. Подготовив второй модуль, свяжите его с первым и оттести¬ руйте их совместно. Добейтесь, чтобы интерфейс между этими модулями работал должным образом. Перейдите к третьему модулю, свяжите его с остальными, оттестируйте интерфейс и продокументируйте проделанную работу. Продолжайте действо¬ вать таким образом, пока не разработаете, не объедините, не отладите и не продокументируете все модули программы. Шаг 9. Разработайте документацию пользователя. Подготовьте руководство, сообщающее предполагаемым пользователям, как работать с вашей программой. Руководство должно быть всеобъ¬ емлющим и описывать каждую существенную черту вашей программы; оно должно включать сведения о настройке про¬ граммы, учебный раздел для новых пользователей и справочную информацию для опытных пользователей. 36
Кроме того, подготовьте хелп-кадры и прочую внутреннюю документацию, которая потребуется в вашей программе. Она должна выдаваться пользователю по его требованию. Шаг 10. Испытайте и оцените свою программу. Испытания проводятся в течение всей разработки. Когда программа и эксплуатационная документация будут подготовлены, попробуйте дать их тем, для кого они предназначаются. Научите этих людей работе с вашей программой, снабдите их пользовательской документацией, а затем предложите опробовать программу для выполнения конкретных задач, определенных вами заранее. Проследите, как пользователи будут использовать программу и как они ее примут, т. е. насколько она им понравится. Не удивляйтесь, если они обнаружат ошибки, пропущенные вами при проверках. Вслед за этими испытаниями пересмотрите свою программу, чтобы исправить ее недостатки и максимизировать ее признание пользователями. Последнее замечание. На самом деле, ни один программист при проектировании и разработке программ никогда не станет в точности следовать этой схеме. Как уже отмечалось, это не жесткие правила, а скорее философия проектирования. Вы должны считать себя свободным изменять описанную стратегию так, чтобы она соответствовала вашему стилю работы и назначению программы. Но при этом не упускайте из виду основного. Помните, что этот подход ориентирован на пользователя, с которым сове¬ туются в начале работы и который оценивает программу в конце ее разработки. Столь же существен при данном подходе упор на модульность и пошаговую разработку программ. В дальнейшем я заполню пропущенные детали. В процессе работы над книгой вам придется постоянно обращаться к изло¬ женной стратегии, поэтому я посоветовал бы вам получше ее запомнить.
Глава 2 С ЧЕГО НАЧАТЬ! В данной главе рассказывается, как увеличить возможности вашего ПК в качестве инструмента разработки программ. Глава начинается с обсуждения оборудования — ПК, видеомониторов, принтеров и дисководов. Она охватывает также важную тему организации архива (не компьютеризованного, а бумажного), который понадобится вам для хранения вариантов программ и распечаток. Во втором параграфе рассматривается программное обеспе¬ чение. Описывается ряд утилит1 и других программ, используе¬ мых при программировании. Эти утилиты будут полезны и вам. В третьем параграфе указывается несколько книг и журналов, с которыми вам следует быть знакомым. ОБОРУДОВАНИЕ Необходимый для разработки программ комплект оборудова¬ ния состоит из клавиатуры, системного блока ПК фирмы IBM и дисплея. Кроме того, можно приобрести принтер и другие до¬ полнительные устройства. Хотя для работы на компьютере иметь эти устройства и необязательно, они сократят затраты времени и дадут вам другие преимущества. Но сначала рас¬ смотрим клавиатуру и системный блок. КЛАВИАТУРА И СИСТЕМНЫЙ БЛОК Естественно предположить, что у вас есть клавиатура и сис¬ темный блок и что вы знаете о них все. Они все более или менее одинаковы. Клавиатуру можно отсоединять, а ее наклон можно изменять. На ней расположены 83 клавиши, в том числе 10 функциональных клавиш и цифровая панель. Когда вы нажимаете на клавиши, то раздается громкий щелчок, обеспечивающий обратную связь. Расположение клавиш подвергалось критике в ос¬ новном за несоответствие клавиатуре пишущей машинки 1 Утилита — вспомогательная программа. — Примеч. пер. 38
IBM Selectric, которую обычно считают фактическим отраслевым стандартом. Парадоксально, что во многих машинах, совмести¬ мых с ПК фирмы IBM, встроена клавиатура Selectric, а в маши¬ нах фирмы, изобретшей эту клавиатуру, — нет. Ряд компаний изготовляет клавиатуры для ПК фирмы IBM, так что если вы недовольны своей клавиатурой, то можете попробовать заменить ее на изделия фирм Key Tronics, Colby, Cherry Electronics или других компаний. В системном блоке используется процессор 8088; для ускорения вычислений в ПК можно дополнительно установить сопроцес¬ сор 8087. ПК может иметь до 640 Кбайт памяти произволь¬ ного доступа (ОЗУ) и содержит 40 Кбайт постоянной памяти (ПЗУ). Ранние модели ПК фирмы IBM поставлялись с ОЗУ объе¬ мом 16 Кбайт, но затем они стали выпускаться с ОЗУ емкостью 64 Кбайт. Память выпускаемых в настоящее время ПК можно нарастить до 256 Кбайт на основной печатной плате, но для дальнейшего наращивания ОЗУ в ПК необходимо установить дополнительную плату. Вообще говоря, чем больше оперативной памяти будет в распоряжении программиста, тем лучше. Для машины с ограниченной памятью трудно построить мощную программу, так как в этом случае приходится идти на компро¬ миссы и к тому же исключено применение некоторых утилит на этапе разработки программы. При разработке программы ваша система должна обладать памятью объемом не менее 128 Кбайт. Лучше, если объем памяти превышает эту величину, а если разрабатываемая программа имеет большой размер, существенно использует графику или по другой причине требует много памяти, то увеличить объем па¬ мяти системы просто необходимо. Программист должен иметь два дисковода, поскольку большин¬ ство пользователей их имеет. Два дисковода позволяют быстрее разрабатывать программы. Согласно одному опросу, проведенному журналом «PC World», система «среднего» пользователя ПК, читателя этого журнала, содержит 256 Кбайт памяти, два дисковода и матричный прин¬ тер. При разработке программного обеспечения для таких поль¬ зователей желательно ориентироваться именно на такую «сред¬ нюю» систему. Создавая программное обеспечение на системе меньшей мощности, вы оказываетесь в неблагоприятном положе¬ нии. Но если вы разрабатываете программное обеспечение для систем с большими возможностями, то это может обернуться снижением числа потенциальных пользователей. Можно дать и более прозаический совет по улучшению вашего ПК. Если временами ваши пальцы не попадают на нужные клавиши, из-за чего на экране появляется невесть 39
что, то эту проблему можно решить следующим простым спо¬ собом: возьмите тюбик эпоксидного клея, зацепите капельку кончиком карандаша и поместите на середину клавиш «Д» и «К». Дайте ей высохнуть и повторите эти действия несколько раз. Затвердевший бугорок будет ощущаться вашими пальцами, сообщая им, где находятся клавиши «Д» и «К», и не позволяя вам сбиться. Поступите таким же образом с остальными клавиша¬ ми, которыми вы часто пользуетесь вслепую, например с цифровой клавишей «5», клавишей «Ввод» и некоторыми функциональ¬ ными клавишами. Это просто и полезно. ДИСПЛЕЙ ПК фирмы IBM может работать с модулятором, управляющим телевизионным приемником, но большинство владельцев ПК пользуются монохромным или цветным монитором1. Управляемый модулятором телевизор устроит тех, кто может обойтись 40-столбцовым дисплеем, не требователен к качеству изображения и работает за дисплеем не более, скажем, 30 мин в сутки. Качество изображения в основном зависит от качества теле¬ визора. Если это дешевый аппарат или старый приемник, поте¬ рявший контрастность, разрешающую способность и сходимость луча, то работа с ним скорее всего будет утомлять глаза. Некоторые используют в качестве дисплея черно-белые телеви¬ зоры. Качество изображения у них несколько выше, чем у цветных, но теряются преимущества цвета. Если вам приходится выбирать между цветным и черно-белым телевизором, то выбирай¬ те цветной. Преимущества цветопередачи перевешивают худшее качество изображения. Подавляющее большинство пользователей приобретают в ка¬ честве дисплея видеомониторы. Многие совместимые с ПК компью¬ теры и переносный компьютер IBM PC Portable имеют встроен¬ ный монитор; в этих случаях решение уже принято за пользо¬ вателя. Но даже и тогда, когда решение оставляется самому пользователю, большинству из них требуется повышенное каче¬ ство изображения, обеспечиваемое видеомониторами. Для ПК фирмы IBM можно выбрать либо печатную плату с адаптером1 2 1 Мониторы внешне похожи на телевизоры, но сигнал поступает на монитор не с антенны, а непосредственно по проводам. Если сравнить телевизор с радиоприемником, то монитор следует уподобить «радиоточке» в трансляци¬ онной сети, которая содержит динамик и регулятор громкости, но не имеет настройки на различные станции и соответствующих электронных схем.— При¬ меч. пер. 2 Адаптером (монитора, принтера и т. п.) называется блок сопряжения компьютера с внешним устройством. Адаптеры ПК фирмы IBM представляют собой печатные платы стандартных размеров, вставляемые в стандартные разъемы свободных гнезд («слотов») внутри системного блока. Такая «откры¬ тая архитектура» ПК фирмы IBM позволяет строить систему из нужных поль- 40
монохромного дисплея и принтера (MDA), либо плату адап¬ тера цветного графического монитора (CGA). Первый адаптер управляет одноцветным монитором фирмы IBM, а второй — пред¬ назначен для управления монитором с отдельными каналами красного, зеленого и синего цвета (RGB — монитором), но может управлять также стандартным (не фирмы IBM) моно¬ хромным монитором и композитным* 1 цветным монитором. Аналогичные платы выпускают и другие фирмы. Для приложений, не требующих цвета, лучше всего выбрать плату монохромного адаптера и монохромный монитор. Сов¬ местно с монохромным монитором фирмы IBM этот адаптер по¬ зволяет генерировать на экране очень четкие символы, обра¬ зуемые точечной матрицей 9X14. К ПК фирмы IBM можно подключить и стандартный монохромный монитор (с помощью адаптера цветного графического монитора), но знаковая матрица будет меньше, а изображение окажется не столь четким. Для приложений, требующих цвета, следует воспользоваться платой цветной графики и либо RGB-монитором, либо композит¬ ным монитором, либо, наконец, цветным телевизором. Но лучше выбрать RGB-монитор, так как он обеспечивает очень резкое изо¬ бражение, допускающее отображение 80 столбцов текста. Компо¬ зитный монитор и цветной телевизор, как правило, не обеспе¬ чивают резкости изображения, достаточной для вывода 80 столбцов. Кроме фирмы IBM, адаптеры дисплеев и мониторы выпускают и другие компании. Некоторые из этих плат способны рабо¬ тать как с монохромными мониторами с высоким разрешением, так и с цветными мониторами. Если ваши потребности не сводятся только к монохромному или только к многоцветному выводу на экран, то имеет смысл рассмотреть возможность приобре¬ тения этих плат. Есть несколько высококачественных цветных мониторов, кото¬ рые будут работать с ПК. Они различаются главным образом ценой. Среди ведущих изготовителей таких мониторов можно ука¬ зать фирмы Amdek, Nippon Electric Company (NEC) и Taxan. Качество их мониторов достаточно высоко, их легко купить и они зователю модулей. В частности, сама фирма IBM выпускает не менее пяти различных адаптеров дисплеев; о двух из них говорится в данной книге. Остальные начали выпускаться, когда книга была уже написана. Адаптеры дисплеев выпускают и другие фирмы; из них наиболее широко распространен адаптер фирмы «Геркулес», совместимый с адаптером MDA фирмы IBM и позволяющий дополнительно формировать на том же экране гра¬ фическое изображение размером 720X348 точек.— Примеч. пер. 1 В отличие от RGB-мониторов, композитные мониторы получают сигналы всех трех цветов по одному каналу (проводу), а затем разделяют их. Соответственно качество их изображения хуже, а схема сложнее, но они дешевле; выпускаются в большом количестве (для применения с видеомагни¬ тофонами).— Примеч. пер. 41
часто продаются со скидкой. Эти фирмы продают как композит¬ ные, так и RGB-мониторы. Как правило, монохромные мониторы меньше утомляют глаза, чем цветные. Если вы собираетесь сидеть за экраном долгими часами, а цвет для вас необя¬ зателен, то подумайте всерьез о монохромном мониторе. Если вы решитесь им обзавестись, то учтите, что размер и качество экрана важнее цвета его фосфора. Наиболее распространены три цвета экрана: белый, янтарный (светло-желтый) и зеленый. В слабоосвещенном помещении глаз более чувствителен к зеле¬ ному цвету, так что если вы собираетесь работать' в полузатем- ненном месте, то лучше приобрести монитор с зеленым фосфором. Если вы будете пользоваться монитором в более светлом помеще¬ нии, то лучше купить монитор с янтарным или белым экраном. Какой бы цвет монитора вы ни выбрали, его экран должен иметь размер не менее 30,5 см (12 дюймов) по диагонали. Экран меньшего размера труднее читать и он неудобен при продолжительной работе. Экран большего размера не нужен и к тому же при нормальном расстоянии от лица (50—70 см) им неудобно пользоваться. fe ПРИНТЕР Можно назвать две причины, по которым для серьезного про¬ граммирования необходимо иметь принтер. По-первых, он позволя¬ ет выводить на бумагу тексты разрабатываемых программ. Такие листинги облегчают разработку программ, так как нужная информация обычно быстрее и легче находится в распечатке, а не при просмотре программ на экране. К тому же листинг является постоянно существующей копией программы, которую вы не сможете случайно стереть, заменить или повредить несколь¬ кими небрежными прикосновениями к клавишам. Хотя аккурат¬ ность в работе уменьшает вероятность таких неприятных слу¬ чайностей, иногда они все же происходят. Многие программисты избежали больших неприятностей благодаря сохраненным ими распечаткам. Во-вторых, принтер позволяет разрабатывать программы, осу¬ ществляющие вывод на бумагу. Не все программы генерируют от¬ четы, но серьезные программы, как правило, это делают. Невоз¬ можно представить систему обработки текстов, управления базой данных или программу финансового анализа без вывода от¬ четов на бумагу. Большинству программистов приходится выбирать между то¬ чечно-матричным принтером ударного действия и принтером с по¬ вышенным качеством печати1. Большинство принтеров последнего рода содержит элемент типа «ромашка» или «цилиндр», поз¬ 1 Letter-quality: качество печати, достаточно хорошее для деловых писем на бланке учреждения, как у хорошей канцелярской пишущей машинки.— Примеч. пер. 42
воляющий печатать полностью сформированные знаки. Качество их печати выше, чем у матричных принтеров, но зато принтеры повышенного качества печати медленнее работают, сильнее шумят, дороже стоят и, как правило, менее надежны, чем матричные принтеры. Кроме того, они лишены графических возможностей матричных принтеров. Принтер повышенного качества печати не¬ обходим каждому, кто всерьез занимается обработкой текстов, но обычно эта задача не является главной для программис¬ тов. Если ваш компьютер будет выводить на печать преиму¬ щественно тексты программ, графику и генерируемые компью¬ тером отчеты, то лучше приобрести матричный принтер. С ПК фирмы IBM чаще всего используют два матричных принтера: матричный принтер (IBM Matrix Printer) и графи¬ ческий принтер IBM (IBM Graphics Printer). Внешне они выглядят одинаково, но графический принтер обладает более обширным набором знаков и более богатыми графическими возможностями. Фирма Epson Corporation выпускает принтеры серий MX, FX и RX, похожие на принтеры фирмы IBM. Принтеры фирмы Epson дешевле, чем принтеры фирмы IBM, и могут работать сов¬ местно с ПК фирмы IBM, но лишены некоторых графических возможностей графического принтера IBM. Если вас графика не интересует, то вы сможете сэкономить немного денег, купив принтер фирмы Epson вместо принтера фирмы IBM. Принтеры фирм IBM и Epson приобрели хорошую репу¬ тацию за свое качество и надежность, но они медленно работают, имеют тенденцию заминать бумагу, их кнопки управления рас¬ положены сверху, а не спереди и их крышки мешают следить за движением бумаги. Принтеры фирм Okidata и C.Itoh во многих отношениях их превосходят и любому владельцу ПК, собирающе¬ муся купить высококачественный матричный принтер, стоит вни¬ мательно рассмотреть эти устройства. Например, принтер Okida- ta92 стоит примерно столько же, сколько графический принтер IBM, но работает быстрее, его кнопки управления расположены спереди и он реже заминает бумагу. Фирмы Apple и Digital Eguipment Corporation (DEC) продают принтеры фирмы C.Itoh под собственной торговой маркой, и качество и надежность этих принтеров проверены на деле. (Принтер C.Itoh встроен в компью¬ терную систему Macintosh фирмы Apple.) Кроме того, на рынке имеется и множество других высоко¬ качественных принтеров, но не все они продаются так же хорошо, как принтеры трех вышеупомянутых марок. Какой бы из них вы ни приобретали, убедитесь предварительно, что сможете найти место, где можно их починить, не посылая обратно на фабрику в Токио, Тайбэй или Сеул1. В общем, безопаснее покупать изделия фирмы IBM или других ведущих фирм. 1 В СССР наиболее популярны принтеры фирм Epson и Juki. Фирма Juki имеет свой технический центр в Москве. — Примеч. пер. 43
МЕНЕЕ ВАЖНОЕ ОБОРУДОВАНИЕ Жесткий диск представляет несомненную ценность для про¬ граммистов, поскольку он работает намного быстрее дискетных дисководов и имеет намного больший объем. Он необходим, если программирование поглощает существенную часть вашего рабоче¬ го времени или если ваши задачи требуют жесткого диска. Цены на жесткие диски и их контроллеры1 падают и в конце 1984 г. ПК можно было снабдить жестким диском менее чем за 1000 дол. США1 2. Жесткие диски для ПК фирмы IBM и совместимых машин предлагают многие компании. Но история отрасли учит, что не только снижаются цены, но и разоряются компании. Мораль: покупайте только у хорошо известных изгото¬ вителей. Надежнее всего иметь дело с компанией, название которой состоит из трех первых букв: IBM. Если вы живете в районе, где часто бывают скачки напря¬ жения в сети, то купите стабилизатор напряжения3. Если вы жи¬ вете недалеко от подстанции, то обычно никаких проблем не во¬ зникает. Но если вы живете на окраине, в конце электрической линии, то, вероятно, ощущаете колебания напряжения. Вы узнаете об этом, когда свет в вашем доме на какой-то момент тускнеет, а затем вновь становится ярким, или по другим оче¬ видным признакам колебания напряжения. Такие изменения в на¬ пряжении могут существенно повредить вычислительную технику. Они вызывают пиковые нагрузки, которые могут разрушить элек¬ тронные схемы. Если вы решили обзавестись стабилизатором, то найдите такой, который снабжен общим выключателем и достаточным числом розеток, позволяющим подключить к нему ПК, принтер, монитор и прочее оборудование. Если стабилизатор вам не нужен, то обзаведитесь удлинителем с общим выключателем, чтобы вы могли включать и выключать всю свою вычислительную технику одним движением. В конце 1984 г. стабилизатор стоил около 100 дол. Гораздо дешевле сделать его самому. Если вам захочется этим заняться, то обратитесь к разделу Ciarcia’s Circuit Cellar журнала BYTE за декабрь 1983 г. 1 Блоки сопряжения компьютера с дисководами и накопителями на магнит¬ ных лентах называют Не адаптерами, а контроллерами; различие в названиях сложилось исторически; по существу, адаптеры и контроллеры — это синонимы. — Примеч. пер. 2 В середине 1987 г. — за 350 дол. США, емкость типичного диска выросла в 4 раза (с 5 до 20 Мбайт), а габариты уменьшились в 2 раза. За 1100 дол. можно приобрести диск емкостью 60—80 Мбайт. — Примеч. пер. 3 Точнее говоря, это не только стабилизатор, но и фильтр, предохраняющий ПК от высоковольтных «пиков» напряжения. В США такое устройство назы¬ вается «surge suppressor», буквально — «подавитель скачков». В сети иногда возникают очень кратковременные, но сильные скачки напряжения до 1000 В и даже выше. Высококачественные фильтры защищают оборудование от скачков до 6000 В. — Примеч. пер. 44
ВАШЕ РАБОЧЕЕ МЕСТО Рабочее место — это комбинация мебели и оборудования, за которым работает человек. Если вы работаете с компьютером, то имеете рабочее место, хотя, наверное, и не называете его так. Существуют хорошие и плохие способы организации рабочего места, но не всегда ясно, какие из них хорошие. Если ваше рабочее место плохо организовано, а вы пользуетесь им более чем час в день, то, возможно, чувствуете такие неприятные ощущения, как утомление глаз, боль в спине, руках или запястьях. Очевидный выход — реорганизовать свое рабочее ме¬ сто. Предлагаем несколько советов. • Обзаведитесь хорошим стулом, достаточно жестким и хоро¬ шо поддерживающим нижнюю часть спины. Если ваши ступ¬ ни не достают пола, то заведите скамеечку или нечто в том же роде, чтобы ставить на нее ноги. • Поставьте свою клавиатуру примерно на высоте локтей (руки сбоку от тела). Вы не должны тянуться к клавиа¬ туре вверх или через стол. Клавиатура должна находиться сантиметров на 10—20 ниже высоты обычного письменного стола. Если вам удается поднять сиденье вашего стула, то это решит задачу при условии, что вы можете упереть ступни во что-нибудь прочное. Вы должны иметь возмож¬ ность придвинуться к столу и поставить под него ноги. • Установите дисплей на расстоянии около 60 см от лица, примерно на линии взгляда (когда вы смотрите прямо впе¬ ред) или чуть ниже. Большинство пользователей предпочи¬ тают ставить дисплей на системный блок, непосредственно за клавиатурой. • Наладьте освещение так, чтобы свет не отражался от эк¬ рана дисплея и чтобы не было ярких источников света позади экрана или перед ним. Ваши глаза должны адаптиро¬ ваться к яркости дисплея, а не расположенных поблизости от него конкурирующих источников света. Требования к хорошему рабочему месту суммированы в рис. 2.1. Совсем не обязательно покупать дорогую дубовую мебель руч¬ ной работы. Можно приспособить недорогой стул или другую имею¬ щуюся в вашем учреждении мебель. Но если этого оказыва¬ ется недостаточно, чтобы выполнить приведенные выше рекомен¬ дации, то обратитесь в магазин уцененной мебели, сделайте себе мебель сами или добудьте ее каким-нибудь иным способом. АРХИВ Люди по-разному относятся к картотекам и скоросшивателям, и основы этого отношения, наверное, закладываются в раннем детстве. Если вы считаете, что аккуратность и порядок важны, 45
Рис. 2.1. Рабочее место программиста. Важно, чтобы стул хорошо поддерживал спину, клавиатура распола¬ галась примерно на уровне локтей, а монитор — на расстоянии около 60 см от лица на линии взгляда или чуть ниже. Очень важно, кроме того, чтобы освещение не мешало работать (источник света не дол¬ жен отражаться от экрана и не должен светить прямо в глаза) то скорее всего способны оценить удобство картотек и скоро¬ сшивателей. Если вы относитесь к таким вещам с меньшим уважением, то, наверное, рассматриваете архивизацию как нудное занятие, которого желательно избегать. Я бы предпочел не занимать определенной позиции по этому вопросу, так сильно связанному с индивидуальным стилем работы. К сожалению, нейтрально относиться к нему невозможно, так как по крайней мере в области программирования я склонен к требовательности в отношении аккуратности и порядка. Программисту, который держит свои рабочие материалы — лис¬ тинги1 программ, документацию, дискеты и т. п. — в хорошо 1 Листинг — то же, что распечатка текста программы.—Примеч. пер. 46
организованном архиве, живется лучше, чем тем, кто определя¬ ет их расположение, полагаясь на свою память. Все мы имеем друзей, чьи письменные столы похожи на свалку книг, журналов и всяких обрывков, и часто считаем их блистательными чудаками. Есть поверие, что такие люди точно знают, где и что у них лежит, и что они могут найти все, что захотят и когда захотят. Иногда им это действительно удается, но относитесь все же к подобным утверждениям со здоровым скепсисом. Программист, который так обращается с рабочими материалами, играет с огнем. В программировании запас надежности слишком мал, а сделать ошибку слишком легко. Программы должны быть совершенно точ¬ ны, а хранимые нами версии программ и прочие записи должны сохраняться без малейших изменений. Многое из того, что программист делает сегодня, основывается на том, что было сде¬ лано им вчера: будь то использование кусков старых программ, поиск ошибок в определенном модуле или составление руковод¬ ства пользователя. При любой такой работе необходимо иметь возможность быстро найти использовавшиеся ранее материалы. Недостаточно быть только более или менее уверенным, что вы на¬ шли именно то, что искали. Вы должны быть уверены абсолютно точно, так как выполняете точную работу. Более того, вы не должны тратить свое время на то, чтобы рыться в горах бумаг, перебирать ящики, просматривать книжные полки и заниматься прочими бессмысленными делами. Вам понадобится несколько хранилищ. Начните с ящика для дискет — пластмассовой коробки с раскрывающейся прозрачной крышкой, в которой помещается около 50 дискет. Поставьте ее на стол возле компьютера и держите в ней часто используемые вами программы. Я бы посоветовал вам использовать разные отделения для программ-утилит, основных и страховых1 копий дискет с той программой, над которой вы сейчас работаете, пустых дискет и дискет прочего назначения, которые вам пона¬ добятся в ходе работы. Такая коробка удобна и для хранения под рукой часто используемых программ. Закончив разработку проекта, для дальнейшего хранения пере¬ ложите программные дискеты в специальные пластмассовые коробки. Я бы посоветовал вам для начала завести с полдюжины таких коробок и держать в них рабочие копии своих программ. Пластмассовая коробка вмещает около 20 дискет и стоит меньше пяти долларов. Если покупать их оптом, то они обойдутся еще дешевле. Надпишите коробки, поставьте их на полку и обращай¬ тесь к ним по мере надобности. Для хранения различных 1 Страховые копии создаются из соображений безопасности, имея в виду возможное случайное повреждение основного экземпляра данных (программ, собранной информации и т. п.). — Примеч. пер. 47
программ, а также для того, чтобы не путать дискеты разных компьютеров, удобно иметь коробки, отличающиеся по цвету. Если вы достаточно много программируете, то поставьте спе¬ циальный шкаф для архивного хранения листингов программ, дискет, документации, сведений о приобретении оборудования и программного обеспечения, копий статей и прочих важных мате¬ риалов. Заведите разделители подборок и надпишите таблички с названиями. Потратьте некоторое время на то, чтобы хорошо организовать свой архив. Критерий успешности этой работы — время, за которое вы сможете найти все, что пожелаете. Вы должны уметь открыть ящик шкафа, найти по табличке раздел и извлечь то, что ищете, не более чем за 10 с. Если на это вам требуется больше времени, то организацию архива необ¬ ходимо усовершенствовать. Хотя на создание архива уйдет много времени, в долгосроч¬ ном плане это уменьшит работу, устранит путаницу и избавит вас от многих забот. ДИСКЕТЫ Покупайте только высококачественные дискеты. Не обязатель¬ но покупать самые дорогие: просто избегайте сомнительных деше¬ вых дискет. Высококачественные дискеты лучше всего покупать со скидкой — по почте. Если вы хотите дать заработать местному магазину компьютеров, то покупайте в нем дорогие вещи: компьютеры, дисководы, принтеры и т. п. Каждый программист понимает, как важно заботиться о дис¬ кетах. Для этого не требуется ничего, кроме наличия здравого смысла. Держите дискеты в коробках, когда ими не пользуетесь, чтобы они не пылились. Не работайте с ними, когда едите жареный картофель, и не давайте разгуливать по ним своей кошке. Кроме того, будьте осторожны и избегайте менее очевид¬ ных опасностей. «Катышки» от резинки, образующиеся при стира¬ нии сделанных карандашом записей, опасны для дискет, так что не разбрасывайте эти катышки там, где кладутся дискеты. Для дискет опасны порошок от блох (если у вас есть домашние животные), мел (если вы преподаете), диатомовый ил (если у вас есть бассейн или аквариум), табак (если вы курите) и слюна (если у вас есть собака или маленький ребенок). По-видимому, никто в точности не знает, какова продолжи¬ тельность жизни дискет. Особенно скрытны в этом отношении их изготовители и они не станут прямо отвечать на ваши во¬ просы. Ответы, которые получал я, варьируются от «около года» до «вечно». Похоже, что условия хранения не имеют особого значения. Поэтому я не могу дать вам лучшего совета, чем пользоваться дискетой не дольше года, иметь хороший запас дис¬ кет под рукой и не работать все время с одними и теми же дискетами. 48
Для программиста дискеты — все равно, что бумага для писа¬ теля. Это расходуемые материалы, необходимые для выполнения работы, и к ним не следует относиться так, будто они изготовлены из драгоценных металлов. Есть хороший тест, позволяющий определить, чего вы стоите: «Скажите, сколько у вас пустых дискет?» Если вы имеете меньше пяти совершенно новых пустых дискет, то вы вредите самому себе. Отправляйтесь — нет, лучше позвоните в хорошую, надежную фирму, торгующую по почте, и закажите десяток. А лучше купите сразу две коробки. Заказывайте только хорошие дискеты. ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ Программистам, работающим на ПК, особенно повезло в отно¬ шении разработки программ, поскольку версия языка Бейсик для этого компьютера и его DOS обладают многочисленными командами, помогающими программисту в его работе. Среди них можно назвать команды: • RENUM— перенумеровать строки программы; • MERGE — слить две отдельные программы в программной памяти интерпретатора языка BASIC; • DISKCOPY и COPY — соответственно скопировать всю дис¬ кету или один ее файл; • TRON и TROFF — трассировка, показ номера выполняемой строки программы. Во многих версиях Бейсика и DOS, предназначенных для других компьютеров, таких утилит нет или они доступны только в качестве отдельных программ, что затрудняет их использо¬ вание. В некоторых версиях отсутствуют даже такие основопо¬ лагающие команды, как команды DOSa COMP, DIR, ERASE и TYPE или команда DELETE языка Бейсик. В дополнение к возможностям языка Бейсик и DOS, ПК фирмы IBM и большинство совместимых с ними машин снабжены неплохим построчным редактором, который позволяет програм¬ мисту легко создавать, редактировать и дублировать строки тек¬ ста на языке Бейсик. Фирма IBM сочла нужным предложить редактор текстовых файлов (EDLIN), который хотя и не особенно удобен, но прост в освоении и вполне пригоден для подготовки пакетных файлов1 и программ на языке ассемблера. Учитывая все это, нуждается ли программист в чем-нибудь еще? Да, нуждается. Программисту очень пригодятся такие ути¬ литы. • Анализатор перекрестных ссылок. Он сообщает, какие стро¬ ки вызываются из других строк с помощью операторов GOTO и GOSUB распознает любой вызов несуществующих строк. 1 О пакетных файлах (батч-файлах) см. в гл. 3.-—Примеч. пер. 49
Это помогает программисту понять программу, определить, как повысить ее эффективность и предотвратить переход на несуществующие строки. • Составитель списка переменных. Он перечисляет все пере¬ менные, функции и массивы, употребляемые в программе. Полезен как при подготовке документации, так и при со¬ ставлении программ, позволяет избежать случайного по¬ вторения имен переменной, функции или массива. • Программа глобального поиска и замены. Просматривает программу в поиске определенной строкй символов, которая может состоять из любого сочетания цифр, букв и специальных знаков, и заменяет ее на указанную строку. С помощью такой утилиты можно очень быстро осущест¬ вить многочисленные модификации разрабатываемой про¬ граммы. Кроме того, она дает возможность найти некоторую часть программы и определить, присутствует ли в программе указанная строка символов или нет. • Уплотнитель текстов на Бейсике. Удаляет из программы примечания и дополнительно сжимает программу, помещая возможно большее число операторов в возможно меньшее число строк. Сжатие часто уменьшает объем программы на целых 50 % и значительно увеличивает скорость ее работы. Уплотнитель позволяет программисту разрабаты¬ вать программу так, чтобы ее было легко читать, помещая для этого в каждую строку только по одному оператору и снабжая текст множеством примечаний, а затем с помощью компьютера оптимизировать эту программу, максимизируя скорость ее работы и минимизируя требования к диско¬ вой и оперативной памяти. Кроме того, сжатие улучшает защиту программы, так как оно затрудняет ее чтение. Компилятор Бейсика. Преобразует текст на Бейсике, кото¬ рый должен был бы интерпретироваться при выполнении в команды машинного уровня, выполняемые непосредствен¬ но. В результате получается программа, которая работает быстрее, но обычно требует большего объема дисковой и оперативной памяти. Дополнительные достоинства компи¬ лятора — лучшая защита программы и возможность исполь¬ зовать компилятор как отладчик текста, так как он про¬ веряет синтаксис всех строк программы, помогая тем самым программисту найти все ошибки такого рода. • Форматизатор текстов на Бейсике. Преобразует стандарт¬ ный листинг в более удобный для чтения формат, помечая, чтобы раскрыть структуру программы, операторы FOR-NEXT, IF-THEN, WHILE-WEND, а также разнося операторы по одному в строку и выделяя примечания. • Редактор текстовых файлов. Осуществляет те же функции, что и редактор EDLIN, но более удобен в работе. 50
Только вы сами сможете определить, какие из этих утилит вам действительно нужны. Однако четыре первые утилиты необ¬ ходимы для любой серьезной работы. Из остальных утилит некоторые необходимы для работ определенного типа. Так, компи¬ лятор нужен, если вы разрабатываете программу, которая будет часто использоваться, ибо повышенная скорость работы откомпи¬ лированной программы означает уменьшение времени ее выпол¬ нения, сокращение затрат человеко-часов и прочих расходов, а также увеличение общей эффективности программы. Форматиза- тор нужен в тех случаях, когда особенно важно, чтобы вашу программу было легко читать, например, если вы пре¬ подаете, работаете совместно с другими программистами, раз¬ рабатываете очень большую и сложную программу и в некоторых других ситуациях. Редактор текстовых файлов нужен тогда, когда вы много работаете с такими файлами, так как, хотя EDLIN и вполне приемлем для простых задач по редактиро¬ ванию файлов, его возможности очень ограниченны, а исполь¬ зование сопряжено с большой затратой времени. ПК фирмы IBM очень популярны, и многие талантливые программисты обратили свои способности на разработку про¬ грамм-утилит, выполняющих одну или несколько из только что упомянутых функций. Насколько мне известно, ни один пакет утилит не делает все вышеперечисленные операции, но, вероятно, вам это и не требуется. Ниже приводятся краткий список и описание имеющихся в продаже изделий. Этот каталог далеко не полон, но достаточно представителен. Тот факт, что некоторая программа включена в мой список, еще не означает ее одобрения, а указывает только на то, что она выполняет названную функцию. Приводимые для справки цены, насколько мне известно, верны, но я тем не менее не гарантирую их правильность. ПАКЕТЫ ПРОГРАММ Фирма IBM продает пакет программ, называемый BASIC Pro¬ gramming Development Sistem (система разработки программ на Бейсике), ценой 130 дол., программы-утилиты которого выпол¬ няют ряд вышеперечисленных функций. В частности, в пакет вклю¬ чен анализатор перекрестных ссылок, который можно использовать как для поиска перекрестных ссылок, так и для получения списка используемых переменных, форматизатор текстов, «Струк¬ турный препроцессор Бейсика», являющийся уплотнителем тек¬ стов на Бейсике и редактор текстовых файлов. * Фирма Softool Systems выпускает пакет BASIC Development System (система разработки на Бейсике) ценой 79 дол., возмож¬ ности которого включают поиск перекрестных ссылок, составление 51
списка переменных, сжатие и распаковку текстов на Бейсике, пошаговую трассировку и перенумерацию строк с перестанов¬ кой. Фирма Norell Data Systems Corporation выпускает пакет AUTODOC BASIC Utilites (утилиты автодокументирования Бей¬ сика) ценой 50 дол., включающий анализатор перекрестных ссылок, составитель списка переменных и утилиту удаления при¬ мечаний. Фирма Ensign Software продает пакет Cross Reference (пере¬ крестные ссылки) ценой 25 дол., который обеспечивает как анализ перекрестных ссылок, так и составление списка переменных. Отделение General Publishing фирмы Prentice-Hall выпус¬ кает пакет Cross-Reference (перекрестные ссылки) ценой 30 дол., обеспечивающий составление списка переменных с информацией об их использовании. Фирма BASIC Business Software предлагает пакет IBM BASIC Utilites (утилиты для BASICa IBM) ценой 95 дол., обеспечиваю¬ щий анализ перекрестных ссылок, составление списка перемен¬ ных, форматизацию текстов на BASICe, редактирование текстовых файлов и некоторые другие возможности. Компиляторы с языка BASIC поставляются фирмами IBM Corporation (300 дол.), Microsoft (395 дол.) и Softech Microsys¬ tems (225 дол.). Перечисленные пакеты дают вам общее представление о том, какие типы утилит существуют. Кроме них, имеется и множество других утилит. Более того, эти программы модифицируются, и постоянно появляются новые программные изделия. Короче говоря, не ограничивайтесь этим списком. Посетите свой магазин персональных компьютеров, ознакомьтесь с журнальной рекламой и посоветуйтесь с друзьями. Посмотрите, что могут делать различные утилиты, насколько их возможности соответствуют вашим потребностям, и что рекомендуют журнальные обзоры, про¬ давцы и другие программисты. ВАШ КЛУБ ПОЛЬЗОВАТЕЛЕЙ Разработчики многих программ-утилит отказались от своих авторских прав в пользу общества, т. е. не требуют платы за их использование и разрешают свободное копирование. Такие программы обычно имеются в библиотеках клубов пользова¬ телей. Кроме того, в клубах пользователей нетрудно получить допол¬ нительную информацию о применяемых для разработки программ утилитах, которые могут отвечать вашим потребностям. Если вы еще не принадлежите к такому клубу, вступите в один из них. Даже если вы отшельник по натуре и ненавидите общество, бесплатные программы и консультации, которые вы получите,— достаточная причина для вступления в такой клуб. 52
КНИГИ И ЖУРНАЛЫ Самый лучший источник информации о ПК, программирова¬ нии и новом оборудовании — книги и журналы. Серьезный про¬ граммист, работающий на ПК, скорее всего подписывается на несколько журналов и имеет целую полку книг о вычислитель¬ ной технике. Интересующие нас издания можно разбить на три основные категории. • Журналы. Содержат программы, описывают приемы про¬ граммирования и сообщают новости о разработке про¬ граммного обеспечения и оборудования. • Книги о ПК. Содержат более широкую по охвату, чем журнальные статьи, информацию о ПК. • Книги общего содержания. Содержат сведения по интере¬ сующим программистов вопросам, в том числе по методике программирования, оборудованию и о рекомендуемом лите¬ ратурном стиле. В данном параграфе приводится краткое описание публика¬ ций, которые кажутся мне особенно полезными. Некоторые из этих публикаций просто необходимы программистам, другие — нет. Список далеко не полон, но все, что в него включено, несомненно, полезно. Если вы еще не подписались на журналы и не имеете книг, то можете начать с этого списка. книги Указанные ниже книги необходимы каждому серьезному программисту. BASIC изд. Microsoft Corp, (руководство по языку Бейсик), поступающее совместно с ПК фирмы IBM. Это наиболее авто¬ ритетное издание в том, что касается кассетного, дискового и расширенного Бейсика фирмы IBM. Disk Operating System (дисковая операционная система), изд-во Microsoft Corp.— руководство по DOS для ПК фирмы IBM. Книга несколько раз перерабатывалась. Версия DOS 2.1 была опубликована в сентябре 1983 г. Technical Reference (техническое руководство по соответ¬ ствующим ПЭВМ), изд-во IBM Corporation. Содержит главным образом сведения по компьютерам IBM PC и PC/XT. Это издание адресовано владельцам ПК фирмы IBM, но владель¬ цам совместимых компьютеров других фирм иметь его не обя¬ зательно. Тем, кто регулярно работает на ПК фирмы IBM или одном из совместимых компьютеров, обычно бывают нужны сле¬ дующие книги: Held. IBM User's Reference Manual (справоч¬ ное руководство для пользователей ПК фирмы IBM), изд-во Hayden. Эта книга вводного характера, описывающая Бейсик, 53
DOS (до версии 2.0 включительно) и методику программиро¬ вания. Большинство программистов, в том числе и опытных, наверняка, найдут, что для освоения устройства и работы ПК эта книга полезнее, чем документация изготовителей, которая более пригодна для справочных целей, чем в качестве самоу¬ чителя. IBM PC Expansion and Software Guide (руководство no расширению ПК1 фирмы IBM и его программному обеспечению), изд-во Que. Своего рода Всемирный Каталог изделий для ПК фирмы IBM. Он содержит списки фирм-продавцов оборудова¬ ния, программ и услуг для ПК фирмы IBM. Если вы захо¬ тите узнать, можно ли подсоединить к вашему ПК построчный принтер, работающий со скоростью 300 строк/мин., то ответ на этот вопрос можно получить в данной книге. (Такое присоединение возможно, принтер с интерфейсом стоят 4995 дол.) Phillips, Phillips. Reference Encyclopedia for the IBM Personal Computer (справочная энциклопедия по персональному компьюте¬ ру фирмы IBM в двух томах), изд-во Ashton Tate. Эта энциклопедия содержит определения терминов, относящихся к оборудованию, программному обеспечению и методике програм¬ мирования для ПК фирмы IBM. Некоторые темы, например компилятор с Бейсика, редактор EDLIN и другие широко известные пакеты программ, сопровождаются «мини-учебниками».’ Программистам, которым хочется знать, что происходит внутри их компьютеров, или интересующимся сложными аспектами про¬ граммирования, рекомендуем книги Питера Нортона (Peter Nor¬ ton), публикуемые издательством Brady. Три следующие книги никакого отношения к ПК не имеют, но тем не менее мы советуем их вам проработать. Strunk, White. The Elements of Style, изд-во Macmillan. Это классическая книга о том, как следует писать. Ее объем — 71 страница. В книге предлагается 39 эффективных правил состав¬ ления письменных текстов и эти правила действительно можно понять и применять. Эта книга имела влияние не только на писателей. Она оказала очень сильное воздействие и на про¬ граммистов. Обе приведенные ниже классические работы по тех¬ нике программирования написаны под влиянием изложенных в этой книге идей. Керниган Б. и Плоджер Д. Элементы стиля программиро¬ вания, изд-во Радио и связь, 1984. Керниган и Плоджер сде¬ лали для методики программирования то, что Гильберт и Сулливан сделали для оперетты: они установили стандарты, которые все признают и которым все следуют. В этой книге предлагаются простые правила написания хороших программ и выработки' правильного стиля программирования. 1 Т. е. подключению внешних устройств, установке печатных плат в гнезда системного блока и т. п. — Примеч. пер. 54
Nagin, Ledgard. BASIC with Style, изд-во Hayden. Краткая книга о технике программирования на Бейсике, близкая по духу к книге Странка и Уайта о том, как следует писать. Каждый, кто программирует на Бейсике, должен прочесть эту книгу. ЖУРНАЛЫ Следующие журналы содержат полезную информацию о ПК. PC. Ориентирован на пользователей. Информирует их об обо¬ рудовании, программном обеспечении для ПК и имеющих отно¬ шение к этому компьютеру новостях. Журнал позволяет следить за тем, что происходит в области персональных компьютеров, хотя и не предназначен специально для программистов. PC World. Очень похож на журнал «РС». Это объясняется тем, что в прошлом его ведущие сотрудники создали и изда¬ вали «РС». Редакционные материалы журнала в основном того же рода, что и «РС». Tech Journal for IBM Personal Copmuter Users. Из перио¬ дических изданий, посвященных ПК фирмы IBM, в наибольшей степени уделяет внимание техническим вопросам. Этот журнал необходимо читать каждому серьезному программисту. Содержит в основном статьи и заметки по программированию. Creative Computing. Журнал посвящен теме микрокомпью¬ теров вообще, но содержит постоянные разделы и статьи о ПК. Byte. Лучший из технических журналов, посвященных теме микрокомпьютеров в целом. Очень его вам рекомендую. InfoWorld. Еженедельник, сообщающий новости о промыш¬ ленности микрокомпьютеров. Регулярно публикует самую свежую информацию, какую вы только можете получить об этой области. В отличие от большинства журналов, выходящих в свет обычно через три или более месяцев после завершения редак¬ ционной подготовки номера, InfoWorld работает по недельному графику. Журнал интересен и его обязательно следует читать каждому, кто серьезно интересуется этой отраслью промышлен¬ ности.
Глава 3 ПРИЕМЫ ПРОГРАММИРОВАНИЯ Ознакомившись с вводным материалом двух первых глав, мы переходим к программированию как таковому. В этой главе излагается ряд приемов, знание которых должно облегчить программисту его работу. Предлагаемый материал основан боль¬ шей частью на моем собственном опыте и на опыте знакомых мне программистов. В этой же главе демонстрируется действенный способ придания типичной программе структуры. В ней дается первоначальное описание программы, которая будет использоваться в дальней¬ ших главах. Эта глава знакомит вас с «каркасом» программы, т. е. ее организацией и содержанием, а в последующих главах каркас заполняется деталями. К тому, что сообщается вам в данной главе, относитесь как к набору рекомендаций, а не предписаний, которые следует выполнять безоговорочно. Ваш подход к проектированию програм¬ мы в значительной степени определяется вашим стилем работы и личными склонностями. Никто не может составить книгу правил, которая бы всех устроила. В пользу того, что здесь предлагается, скажу, что и мне, и тем, кого я знаю, эти приемы хорошо служат. Они не были придуманы за письменным столом, а вырабатывались в процессе работы и являются плодом большого опыта. Следуя этим рекомендациям, вы, возможно, обойдетесь без тех неприятностей, о которых позже философски замечают, что «на ошибках учатся». Данная глава содержит ряд приемов программирования. В их числе есть очевидные: «снимайте с файлов страховые копии» и более сложные, например, «пишите программы так, чтобы их было легко читать». Всего в главе приводится 10 приемов. Они не были ниспосланы мне свыше на каменных скрижалях, не были они и пронумерованы римскими цифрами. Но все же это своего рода заповеди: каждая из них начинается с некоторого утвер¬ ждения и сообщает, чего вы не должны делать. 56
1. СНИМАЙТЕ СО СВОИХ ФАЙЛОВ СТРАХОВЫЕ КОПИИ Теряли ли вы когда-либо программу или файл данных? Если нет, то вы первый такой программист в истории. Это случается со всеми, даже с опытными программистами. Диск1 может быть механически поврежден. Такое может слу¬ читься в какой-нибудь день, когда все складывается неудачно, и вы в расстроенных чувствах попытались силой впихнуть дискету в дисковод или при каких-нибудь других обстоятельствах. Кроме того, диск может износиться. Хотя и редко, но такое бывает. Но вероятнее всего, что ошибку сделает человек в процессе работы. Вы можете записать что-то поверх файла или повредить данные каким-то другим способом. Если, по небрежности, вы оста¬ вили диск на старом телевизоре, то он может размагнититься, так как магнит телевизора создает сильные поля. По той или иной причине оглавление диска может испортиться, и нормальный доступ к файлам станет невозможным. Иногда ог¬ лавление удается восстановить, воспользовавшись специальными утилитами, позволяющими добраться к файлам «через черный ход». Но если, скажем, что-то записано поверх файла, то никакая утилита уже не поможет. Единственный способ избежать подобных неприятностей — обязательно снимать с файлов страховые копии. Вы должны копи¬ ровать любые диски, на которые регулярно что-то записываете. В их число входят как диски с программами, так и диски с данными, а также любые вспомогательные диски с утилитами, на которые заносилась какая-либо информация. Снимайте со своих дисков копии регулярно, например каждую неделю или после каждого обновления данных. Так проще. Решите, как часто следует снимать с диска копии и выработайте в себе привычку это делать. Страховое копирование программных дисков отличается от копирования дисков с данными тем, что (по крайней мере, у программистов) программный диск изменяется непрерывно. Во время разработки программа обновляется при каждой замене ста¬ рой версии новой. Как в подобной ситуации лучше осуществлять страховое копирование? Один из распространенных способов — работать с двумя дис¬ ками, обозначенными «Диск 1» и «Диск 2». В основном програм¬ мист работает с диском 1, регулярно сбрасывая на него разра¬ батываемую программу. Время от времени диск 1 копируется на 1 В данном параграфе автор под диском всегда подразумевал дискету, гибкий диск. Жесткие диски, в общем, надежнее, хотя боятся ударов, но потеря, скажем, 20 Мбайт данных при аварии жесткого диска вместо 360 Кбайт на дискете может вызвать катастрофические последствия.— Примеч. пер. 57
В течение дня... В конце дня... Рис. 3.1. Процедура ведения страховых копий, использую¬ щая три диска, предоставляет дополнительные гарантии от потери программных файлов во время разработки про¬ граммы. В течение рабочего дня программист периодически заменяет диск 1 на диск 2 и наоборот, а на диск 3 программы копируются только в конце дня. Следовательно, диск 3 служит страховой копией на случай утери нужного файла как на диске 1, так и на диске 2 диск 2. Как часто? Обычно это зависит от характера програм¬ миста и от того, сколько программных файлов было потеряно за последнее время. Как правило, выбирается некоторый ком¬ промисс, зависящий от бероятности испортить диск 1, вероятно¬ сти того, что он уже испорчен, и объема работы по копированию. Необходимость этой работы можно пояснить таким образом: считайте, что копии диска вы делаете для страховки. Диск 2 — это страховой полис. Если то, что вы на него кс/йируете с диска 1, уже «запорчено», то по своему полису вы ничего не получите. Но всегда есть опасность, что диск 1 уже испортился, а вы этого не заметили. Поэтому я посоветовал бы вам более обдуманно подходить к копированию дисков. Рекомендуемый метод требует трех дисков; он показан на рис. 3.1 и работает следующим образом. • Используются три диска. Обозначьте их «Диск 1», «Диск 2» и «Диск 3». • Сделайте диск 1 главным. Работайте с ним и держите на нем наиболее свежие версии всех программ. • По мере модификации программы периодически переклю¬ чайтесь с диска 1 на диск' 2 и обратно. Заканчивайте сеанс работы с диском 1 в дисководе. • В конце сеанса перепишите результаты своей работы на диск 3. Это ваша «архивная» копия. Вы можете к ней вернуться, если потеряете во время сеанса верные копии как 58
на диске 1, так и на диске 2. Не копируйте программы на диск 3 с помощью программ копирования диска, например команды DISKCOPY операционной системы. Сохраняйте свои программы с помощью команды SAVE интерпретатора Бейсика. Диск 3 — ваш дополнительный страховой полис. Вы обновля¬ ете его один раз в сеанс, он содержит черновые версии программ и не предполагается, что он будет точной копией диска 1. Скорее он содержит моментальные фотографии, снятые с программы в оп¬ ределенные моменты времени. Если и диск 1, и диск 2 будут испорчены, то вы сможете достать из архива диск 3 и с его помощью возобновить работу с начала сеанса. Диск 1 можно целиком переписать на диск 2 только тогда, когда вы будете уверены, что ни один из хранящихся на нем файлов не содержит ошибок. Единственный способ проверить это — выполнить (RUN) содержащиеся на диске 1 программы или загрузить (LOAD) все программы по отдельности и про¬ смотреть их текст. 2. ОСТОРОЖНО СБРАСЫВАЙТЕ ПРОГРАММЫ НА ДИСК При разработке программ вам приходится сбрасывать их на диск бесчисленное число раз. Давая команду SAVE, вы каждый раз рискуете записать программу, над которой работаете, под чужим именем. Последствия могут быть серьезными. Если вы заметили свою ошибку и у вас есть страховая копия только что затертой программы, то ничего страшного не произойдет. Плохо, если вы затерли программу, у которой нет страховой копии; неважно, осознали ли вы ошибку сразу или нет, так как она вскоре себя проявит. Мелкие ошибки могут случаться и тогда, когда, запоминая имена сбрасываемых на диск программ, вы полагаетесь на свою память. Вы можете неточно запомнить имя программы и при сбра¬ сывании оказаться вынужденным его угадывать. Вы начнете осоз¬ навать пределы возможностей своей памяти, когда станете про¬ сматривать оглавление диска и обнаружите, что там есть про¬ граммы, озаглавленные BUDGET1. BAS, BUDG: BAS, BUDGT. BAS и BUDGT1. BAS или каким-то другим набором схожих, хотя и различных,имен. Есть маленькая хитрость, позволяющая разрешить эту про¬ блему. Запишите в первой строке своей программы оператор комментария, который будет выглядеть примерно так: 1 REM SAVE «PROGNAME.BAS», А Вместо PROGNAME запишите имя своей программы. Для сброса программы на диск выведите на экран (LIST) строку 1, забейте пробелами номер строки и слово REM и нажмите на клавишу «Ввод». Программа будет сохранена. 59
Этот прием освободит вас от необходимости запоминать имя программы, а также послужит другой важной цели: строка 1 будет служить идентификатором программы. Имя каждой про¬ граммы должно быть записано в ее тексте на заметном месте. Это необходимо потому, что временами, несмотря на все усилия программиста, программные файлы перемешиваются, и надо иметь быстрый и простой способ посмотреть на программу и узнать ее имя. Вдобавок и самому программисту бывает довольно легко перепутать, над какой программой он работает. Если вы работаете над одной большой программой с простым именем-, например «BUDGET», то едва ли забудете ее имя; но это может очень легко случиться, если ваша программа состоит из нескольких подпрограмм с ничего не говорящими или похожими именами, например НЗЕ, Н4Е и H2I или BUDO, BUD1 и BUD2. Под¬ ведем итог: помещать в текст программы ее идентификатор — хорошая привычка, и это удобно делать в примечании с опе¬ ратором SAVE. Конечно, в строке 1 нет ничего особенного. Можно было бы использовать любой другой номер строки, но единица хороша тем, что это короткое число, а строка 1 стоит в начале про¬ граммы, в самом естественном для названия месте. Интерпретатор Бейсика позволяет сохранять программу тремя способами: • SAVE «имя-файла». Если файл сбрасывается таким спосо¬ бом, то Бейсик хранит ее на диске в плотном двоичном формате, снижая тем самым требования к дисковой памяти. Вы можете просматривать такую программу с помощью команды LIST и изменять ее, но не можете сливать ее с другими программами при помощи команды MERGE. • SAVE «имя-файла», А. Параметр А после имени файла заставляет Бейсик хранить программу как текстовый файл в коде ASCII. Это требует большего места на диске по сравнению с хранением программы в плотном двоичном формате, но вы можете сливать эту программу с другими, используя команду MERGE. • SAVE «имя-файла», Р. Параметр Р после имени файла заставляет Бейсик хранить программу в закодированном двоичном формате, исключая тем самым возможность ее просмотра. Это режим защиты, предотвращающий доступ к тексту программы. Программа, сброшенная с пара¬ метром Р, не может быть приведена в исходное состоя¬ ние, но может выполняться обычным образом. Во время разработки программы ее лучше всего сбрасывать в режиме А, с тем чтобы программы можно было сливать. На этапе разработки программ большинство программистов до¬ вольно часто их сливают, в особенности если они пользуются библиотеками программ или другими наборами программных мо¬ 60
дулей, применяемых как готовые блоки или полуфабрикаты. Стратегия разработки программ, которой в книге придается боль¬ шое значение, уделяет особое внимание модульности, так что иметь возможность сливать программы совершенно необходимо. После того как разработка программы будет завершена, имеет смысл ее скопировать и в дальнейшем сохранять^ в сжатом виде: это уменьшит объем занимаемой ею дисковой памяти и позволит защитить файл. 3. ПЛАНИРУЙТЕ ИСПОЛЬЗОВАНИЕ ПЕРЕМЕННЫХ Многие программисты распределяют переменные по мере раз¬ работки программы и в каком-то смысле берут их «с потолка». Надо писать следующую часть программы, и вдруг программист понимает, что в ней нужна новая переменная, массив или функция. Теперь ему надо решить, какой переменной воспользоваться. Переменную нельзя выделять небрежно, иначе может произойти путаница с другими переменными. Программист старается вспом¬ нить, какие переменные он уже использовал и включает в программу такие, которые еще не были задействованы. В боль¬ ших программах, где могут быть сотни переменных, это трудно сделать. Возможное решение вопроса — воспользоваться каким- нибудь необычным именем. Другое возможное решение — просмо¬ треть листинг программы и проверить каждую используемую в ней переменную. Вам эта работа знакома? Все мы так поступаем и в известной мере можем с такой работой справиться. Если программа невелика, то легко просле¬ дить в уме, как используются все переменные, функции и массивы. Но следует понимать, что при разработке достаточно больших и сложных программ так работать нельзя; иначе мы будем только сами себя обманывать и в конце концов просто запутаемся в переменных. Лучший способ избежать такой путаницы — систематически распределять и прослеживать переменные. Спланируйте исполь¬ зование как можно большего числа переменных до начала кодирования. Решите, какие локальные и глобальные переменные вам понадобятся, а затем с самого начала распределите все, какие сможете. В большинстве программ локальные переменные — это рабочие лошадки; ими временно пользуются в различных частях программы. Они безлики, и их сущность постоянно меняет¬ ся. Глобальные переменные более определенны: обычно они пред¬ ставляют что-то одно во всей программе. Решив, какие переменные вам нужны, составьте их полный список. Для глобальных переменных укажите каждую перемен¬ ную и что она обозначает. Локальные переменные, как уже отме¬ чалось, обычно многократно меняют свой смысл, иногда на очень короткое время, так что фиксировать их содержание нецелесооб¬ 61
разно. Однако список их составьте. Примеры такой документации приводятся в гл. 9 Возможно, что вы не сможете с самого начала предусмотреть все переменные, которые вам понадобятся, и некоторые перемен¬ ные вам потребуется ввести позднее. Когда настанет время это делать, проверьте по своим записям, какие переменные уже ис¬ пользуются. Имея такую документацию, вы можете предотвратить повторное распределение переменных. Введя новую переменную, продокументируйте ее. Короче говоря, тщательно поддерживайте документацию в течение всей работы. В настоящее время специалисты по программной докумен¬ тации считают, что чем более описательными являются имена, тем легче читать программу. Например, если вы собираетесь хранить в некоторой переменной цену для продажи, то такую переменную удобно назвать, например, SALEPRICE1. Аналогично строковую переменную для хранения имен неплохо назвать NAMES$1 2. При работе с локальными переменными нет особого смысла следовать данному правилу, поскольку их названия часто меняются. Но при работе с глобальными переменными это правило использовать целесообразно. Один из недостатков длинных имен — то, что они занимают больше памяти. Насколько больше? Это зависит от числа пере¬ менных, но в большинстве случаев их длина не вызывает серьезных издержек. Аналогичное правило действует и тогда, когда про¬ граммист пользуется не полными словами, а сокращениями. Сокращение, имеющее смысловую связь с тем, что оно пред¬ ставляет, лучше, чем имя, не имеющее с обозначаемым вообще никакой связи. Если, например, вы не хотите вводить имена SALEPRICE и NAMES$, то лучше использовать имена S и N$, чем, например, XI и Q$. S и N$ мнемонически связаны с «ценой при продаже» и «именем», а XI и Q$—нет. Выбор имен для переменных в значительной мере определяется личными предпочте¬ ниями программистов. В данной книге я не склонен пользоваться длинными именами переменных, хотя и стараюсь придать глобаль¬ ным переменным осмысленную мнемонику: таков мой профессио¬ нальный стиль. Возможно, в некоторых программах полные имена были бы более приемлемы, но мой опыт подтверждает, что такой стиль оказывается вполне удобным для широкого круга программ. При распределении переменных нельзя использовать зарезер¬ вированные имена. В их число входят все операторы Бейсика, его команды, названия функций и операций. Вероятно, вы с ними уже знакомы, но для облегчения вашей работы их список пред¬ 1 SALEPRICE — цена (при продаже, англ.). — Примеч. пер. 2 NAMES$ — имена, $— суффикс строковой переменной. Так как символы кириллицы нельзя использовать в именах переменных языка Бейсик, програм¬ мисту либо надо знать английский язык, либо проще пользоваться именами вида CENAPRODAG$. — Примеч. пер. 62
ставлен в приложении к данной книге. Бейсик ПК фирмы IBM имеет богатый словарь, и список зарезервированных слов довольно длинен. В отличие от многих версий Бейсика, запрещающих использование зарезервированных слов в качестве имен перемен¬ ных или их частей, Бейсик ПК фирмы IBM допускает их применение в составе имен. Так, имена переменных ABSOLU- TEMP#,INLET$, RECOS% и AUTOPRICE совершенно законны, в то время как содержащиеся в них зарезервированные слова ABS, LET, COS и AUTO в качестве имен переменных недопустимы. Бейсик ПК фирмы IBM содержит четыре оператора опре¬ деления типа переменных: DEFINT, DEFSNG, DEFDBL и DEFSTR. Использование этих операторов необязательно, но неко¬ торые программисты (особенно привыкшие к более структур¬ ным языкам, например языку Pascal, в которых описания типов необходимы) склонны пользоваться такими операторами. Если операторы описания вводятся, то их следует, как в програм¬ мах на языке Pascal, помещать в начало программы. Некоторые считают, что программист должен формально опре¬ делять все переменные до того, как начать с ними работать. Хотя это мнение, в общем, правильно, в использовании опе¬ раторов определения языка Бейсик есть тонкости, которые иногда могут вызывать затруднения. Во-первых, операторы типа DEF вызывают слабое, а не сильное определение, поскольку выпол¬ няемые операторы всегда имеют приоритет над операторами определения типа. Эта проблема иллюстрируется следующей короткой программой: 10 DEFSNG Е—G 20 Е# = 1/3 30 PRINT E# Если вы введете в ПК эту программу и запустите ее, то в результате на экран будет выведено длинное число двой¬ ной точности. Другими словами, определение в строке 10 всех переменных от Е до G как чисел единичной точности не предо¬ твращает переопределения и использования переменной Е в стро¬ ках 20 и 30 как числа двойной точности. Эта возможность бывает удобна программисту, но она же подрывает те ограни¬ чения, которые операторы определения типа должны были бы на¬ кладывать на использование переменных. Вторая и в некотором смысле более серьезная проблема заключается в том, что с переменными без суффикса (I, 4#, % или £) операторы обращаются в соответствии с типом, определен¬ ным в операторе DEFxxx. Иногда это может вызвать парадок¬ сальные результаты. Одну из таких ситуаций иллюстрирует сле¬ дующая короткая программа: Ю DEFSTR A—D 20 С =123.45 30 PRINT С 63
В результате выполнения этой программы ваш ПК сообщит: «Туре mismatch error in 20 («ошибка в строке 20 — несоот¬ ветствие типов»). Однако все будет превосходно работать, если вы измените программу следующим образом: 10 DEFSTR A—D 20 С = ”123.45” 30 PRINT С Так как в строке 10 программы все переменные от А до D были объявлены строковыми, любая переменная без суффиксов, имя которой попадает в этот интервал, интерпретируется как строка. Таким образом, присвоение в строке 20 программы совершенно законно, хотя для большинства программистов, рабо¬ тающих на Бейсике, такой прием непривычен. Конечно, будет гораздо лучше определять тип этой переменной всякий раз, когда она используется в программе, так как тогда тип станет явен и не останется никаких сомнений. Но если вы будете так поступать, то операторы DEF, в сущности, будут не нужны. При кодировании может оказаться, что, судя по вашим запи¬ сям, некоторая переменная не применяется, но вы не уверены, мож¬ но ли этим записям доверять. На случай такой ситуации очень по¬ лезно иметь утилиту, которая будет создавать список переменных. Эта задача может решаться и с помощью утилиты глобального поиска и замены. Может случиться, что когда надо будет ввести новую переменную, некоторое имя будет подходить с точки зрения мнемоники. Просмотрите программу с помощью утилиты глобаль¬ ного поиска и замены, чтобы выяснить, не задействована ли в ней такая переменная. (Разумеется, используйте утилиту в режиме поиска, а не замены, а если это невозможно, замените имя этой переменной само на себя.) Это позволит вам узнать, можно ли включить в программу новую переменную без кон¬ фликта со старыми. 4. ПИШИТЕ ПРОГРАММЫ ТАК, ЧТОБЫ ИХ БЫЛО ЛЕГКО ЧИТАТЬ Язык программирования Бейсик часто критикуется и специа¬ листами по вычислительной технике, и пользователями за труд¬ ность чтения. Некоторые считают, что сам язык с его гибкой структурой управления, способностью определять структуры дан¬ ных по ходу программы и «зловредным» оператором GOTO, был проклят за своего рода первородный грех, и это проклятье делает любую написанную на нем программу нечитаемой. Однако проблема состоит не только в самом языке Бейсик. Во многом она является следствием плохих примеров и плохих советов по его использованию. Публикуемые в популярных жур¬ налах программы часто только усиливают отрицательное отноше¬ 64
ние к этому языку. Обычно программу на Бейсике невозможно по¬ нять без письменных пояснений. Но если ее логично организовать, снабдить примечаниями и записывать в каждую строку только по одному оператору, она станет легко читаемой. Часто ли вы встре¬ чали программистов, которые работали таким образом? Вероят¬ но, очень редко. Во многих авторитетных источниках приводятся советы, ко¬ торые могут только затруднить работу программиста и сделать менее понятными составляемые им программы. Например, в при¬ ложении 1 руководства по Бейсику фирмы IBM сообщается, что производительность программы можно увеличить, сведя к мини¬ муму использование примечаний и помещая как можно больше операторов в каждую строку. Конечно, эти рекомендации верны, но приводятся они без оговорок. Скорость программы, разуме¬ ется, важна, то же самое можно сказать и о минимизации требо¬ ваний к памяти компьютера. Но, выбрасывая примечания и сжи¬ мая операторы программы, вы сильно затрудняете ее чтение и по¬ нимание ее работы. На самом деле можно иметь легко читаемую и в то же время быстро работающую программу, подготовив две ее версии. Сначала закодируйте программу так, чтобы ее было легко читать, а затем «оптимизируйте» с помощью утилит сжатия или. компиляции. Утилита сжатия типа тех, которые описывались в гл. 2, уберет примечания и упакует операторы программы в воз¬ можно меньшее число строк. Утилиты делают подобную работу гораздо лучше, чем люди. Их не затрудняют длинные строки текста, и они безразличны к примечаниям. С другой стороны, программисту намного легче по¬ нять, что он работает над генератором вывода результатов анали¬ за, если в тексте есть строка, в которой написано: «Генератор вывода результатов анализа». К тому же текст, в котором каждый оператор записан в отдельной строке, легче изменять. Многие считают, что примечания — признак расточительства, дилетантизма и вообще их лучше избегать. То же самое часто думают о записи только по одному оператору в каждой строке. Если вы так считаете, то вы неправы. Забудьте, что говорится в некоторых учебниках программирования, вычеркните из памяти плохие листинги, которые вы встречали в журналах и книгах, а также то, что делает ваш кумир в области программирования. Вместо этого составляйте программы так, чтобы они были ясными и их могли понимать и другие. Тогда вам самим будет легко пони¬ мать и изменять эти программы и уменьшится вероятность ошибок. Следуйте двум простым правилам. Они помогут сделать программу читаемой. • Не экономьте на примечаниях, обозначающих программные модули и подпрограммы и-сообщающих, что в них делается. Пусть примечаний будет достаточно, чтобы сообщить все, что следует. 65 3 Зак. 1488
@ Записывайте в каждую строку только по одному оператору, тогда вашу программу будет легко читать и модифициро¬ вать. После того как вы привыкните к написанным таким об¬ разом текстам, они станут вам нравиться. В таком стиле есть своя элегантная простота. Он создает впечатление органи¬ зованного мышления, хороших профессиональных привы¬ чек, серьезного характера и уважения к коллегам. Эти простые правила могут полностью изменить читаемость программы. Для иллюстрации сравните рис. 3.2 и 3.3. Программа на рис. 3.2 соответствует этим правилам, а программа на рис. 3.3 — нет. Решайте сами, с какой из них вам было бы легче работать. Текст программы можно сделать еще более удобным для чте¬ ния, если воспользоваться одной из утилит форматизации текстов на Бейсике (они описывались в гл. 2). Такие утилиты обычно рас¬ полагают с уступом операторы FOR-NEXT, IF-THEN и WHILE- WEND и, показывая структуру программы, разбрасывают опе¬ раторы по отдельным строкам, выделяют примечания и делают другие полезные вещи, облегчающие понимание листингов. На 0 REM Программа с комментариями, достаточными для читабельности 1 REM Save"A:FIG3-2", А 12000 REM--Получить идентификатор диска с данными-- 12010 INPUT"Введите идентификационный номер диска с данными: ";ID$ 12020 IF LEN(ID|)=0 OR LEN (ID|)>12 THEN BEEP: GOTO 12010 12030 GOSUB 6000:REM запись в Файл ид. номера диска с данными 12040 GOSUB 6250:REM чтение параметров размерности массива 12050 REM--придание размерности новым массивам-- 12060 A=A7.(0):REM размерность массива равна 1 12070 DIM 0$ (А), О (А), 01 (А), 01 7. (А), 027. (А) : REM Фамилия, баланс по счету, месячные платежи, дата ежемесячного платежа, длительность займа (в месяцах) 12060 А:А’Х (А) 12090 DIM Р$ (А), Р (А), 7. (А), Р27. (А) : REM запись в чековой книжке, сумма, номер че¬ ка, дата 12100 REM--Инициализация записи-- 12110 REM-Очистить файлы данных от старых значений- 12120 REM-Данные о ссудах- 12130 FOR А-0 ТО А7. (0) 12140 0|(А)= 12150 0(A)=0 12160 01(А)-0 12170 017. (А) =0 12160 027(А)= 0 12190 NEXT 12200 REM-Данные о платежах- 12210 FOR А = 0 ТО А7. (1) 12220 Р|(А)-"" 12230 Р(А)=0 12240 Р1Х(А)= 0 12250 Р27. (А) = 0 12260 NEXT 12270 ЕЕМ--Прием сведений о пользователе-- 12260 GOSUB 20000:REM обращение к модулю ввода данных 12290 GOSUB 24000:REM сортировка файла 12300 GOSUB 6500:REM запись в файл данных 12310 GOTO 10000:REM возврат в главное меню Рис. 3.2. Распечатка фрагмента программы, содержащей достаточно примечаний, чтобы ее было легко читать 66
0 REM Программа с комментариями, недостаточными для читабельности 1 REM Save"A:FIG3-3", А 12010 INPUT"Введите идентификационный номер диска с данными: ";Юф 12020 IF LEN(ID$)=0 OR LEN (ID$)>12 THEN BEEP: GOTO 12010 12030 GOSUB 6000 12040 GOSUB 6250 12060 A=AZ (0) 12070 DIM Оф (A) , О (A) , O1 (A) , 01 Z (A), O2Z. (A) 12060 A = A7. (A) 12090 DIM Рф(A),P(A),P1Z(A),P2Z(A) 12130 FOR A=0 TO AZ(0) 12140 0$ (A) - 12150 O(A)= 0 12160 01(A)=0 12170 01Z(A)=0 12160 O2Z(A)=0 12190 NEXT 12210 FOR A=0 TO AZ(1) 12220 P$(A)="" 12230 P(A)=0 12240 P1Z(A)=0 12250 P2Z(A)=0 12260 NEXT 12260 GOSUB 20000 12290 GOSUB 24000 12300 GOSUB 6500 12310 GOTO 10000 Рис. 3.3. Распечатка того же фрагмента программы, что изображен на рис. 3.2, но без единого примечания. Хотя операторы языка BASIC легко узнать, основываясь на одной лишь распечатке, невозможно понять назначение этой программы и ее устройство рис. 3.4 показана форматизированная версия программы, изобра¬ женной на рис. 3.2. Бейсик ПК позволяет вставлять в программу примечания либо после оператора REM, либо после знака одиночной кавычки. Некоторые программисты пользуются обоими способами в одной программе. Однако лучше применять только один из них, причем целесообразнее использовать оператор REM, так как он заметнее и его легче увидеть при просмотре текста. По той же причине желательно, чтобы примечания выделялись в тексте программы. Это можно сделать, поместив в начало и конец примечаний какие- нибудь легко различимые знаки, например черточки или звездоч¬ ки. Другой прием — употреблять в примечаниях только строчные или и строчные и прописные буквы; тогда примечания будут отличаться от исполняемых операторов программы, . большей частью записываемых прописными буквами. Ясно, что это не прин¬ ципиальные вопросы, но вам следует их рассмотреть и вырабо¬ тать для себя правила,’которым вы будете следовать в дальней¬ шей работе. Дополнительное замечание по поводу сжатия и компиляции: сохраняйте исходный несжатый текст своих программ. Эти исход¬ ные тексты потребуются при внесении изменений в программы. Утилиты сжатия часто упаковывают строки так плотно, что ста¬ новится невозможно делать вставки. Поэтому для выполнения изменений мы рекомендуем вернуться к исходному тексту и моди¬ 3* 67
фицировать его, а затем снова сжать. Осторожно обращайтесь с исходным текстом. Для безопасности я бы посоветовал хранить его в архиве вместе с распечаткой программы, а не держать вместе с дискетами, которыми вы постоянно пользуетесь. Обязательно распечатывайте исходные тексты своих программ. Листинги сжатых версий иметь не обязательно: они могли бы помочь вам при поиске ошибок в программе, но, прослеживая операторы GOTO и GOSUB, сжатую программу довольно легко сопоставить с исходным текстом. Если в сжатой программе что- нибудь работает неправильно, то постарайтесь воспроизвести эту 0 REM Программа с комментариями, достаточными для читабельности 1 REM Save"A:FIG3-2", А 12000 REM--Получить идентификатор диска с данными-- 12010 INPUT"Введите идентификационный номер диска с данными: ";ID$ 12020 IF LEN(ID$)=0 OR LEN (ID$)>12 THEN BEEP: GOTO 12010 12030 GOSUB 8000: REM запись в файл идент. номера диска с данными 12040 GOSUB 6250'*. REM чтение параметров размерности массива. 12050 REM--придание размерности новым массивам-- 12060 А=АХ(0): REH размерность массива равна 1 12070 DIM О|(А), 0(A), 01(А), . 01X(А), 02X(А): REM Фамилия, баланс по счету, месячные платежи, дата ежемесячного платежаг длительность займа (в месяцах) 12080 А-АХ(А) 12090 DIM Р$(А), Р (А) , Р1Х(А), Р2Х(А): REM запись в чековой книжке, сумма, номер чека, дата 12100 REM--Инициализация записи-- 12110 REM-Очистить Файлы данных от старых значений- 68
12120 RЕМ-Данные о ссудах- 12130 12140 12150 12160 12170 12160 12190 FOR А=0 ТО А7. (0) ! 04(A)--’"' : о(А)=0 : о1(А)=0 : oiz(A)=0 : О2Х(А)=0 NEXT 12200 REM-Данные о платежах- 12210 12220 12230 12240 12250 12260 FOR А-0 ТО АХ(1) : Р|(А):- : Р(А)=0 : рг/.(а)=0 : Р2Х(А)=0 NEXT 12270 REM--Прием сведений о пользователе-- 12280 GOSUB 20000: REM обращение к модулю ввода данных 12290 QOSUB 24000: REM сортировка Файла 12300 QOSUB 8500: Рис. 3.4. Распечатка того же REM запись в файл данных фрагмента программы, что 12,310 был изображен на рис. 3.2, после форматирования с по- REM возврат в главное меню мощью утилиты ошибку в исходной версии и исправляйте ее уже там. Обычно лучше и не пытаться исправлять ошибки в сжатой версии, так как ее операторы упакованы слишком плотно. Это вторая причи¬ на необходимости хранения исходной версии программы. 5. БУДЬТЕ ПОСЛЕДОВАТЕЛЬНЫ ПРИ ПЛАНИРОВАНИИ И ОРГАНИЗАЦИИ ПРОГРАММ Среди творческих людей (а программисты обычно люди твор¬ ческие) последовательность в работе часто не очень популярна. Творческие люди не любят, когда какие-нибудь правила мешают их свободе. Однако в пользу последовательности при программи¬ ровании есть весомый аргумент: при этом уменьшается объем той информации, которую вы должны запомнить и освоить, а следовательно, уменьшается и вероятность ошибок. Если все ваши программы выглядят по-разному, то «тайны» каждой из них вам придется познавать по отдельности. В этом случае каждая новая программа планируется, кодируется и внед¬ ряется «с нуля». Возвращаясь к ней, вы должны заново во всем разбираться. 69
Разумнее строить все программы на основе одной модели. Очевидно, что это не всегда возможно: разные программы осу¬ ществляют различные функции и должны строиться из различ¬ ных блоков. В следующем списке перечислен ряд наиболее часто требуемых работ, все или, по крайней мере, некоторые из них вам придется предусмотреть при проектировании почти любой программы: • выдачу информации на экран и печать; • прием от пользователя вводимых данных; • управление работой программы; $ чтение файлов и запись в них. Для выполнения этих функций в различных программах, как правило, оказывается возможным использовать одни и те же (или очень близкие) подпрограммы. Если вы так поступаете, то ваши программы становятся очень похожими друг на друга, а в результате оказывается легче их понимать и с ними работать. Очевидно, что такой подход к проектированию не может понра¬ виться всем программистам и что некоторые программы невоз¬ можно создать таким образом. Однако к этому следует стремить¬ ся. Вы быстро убедитесь в удобстве такого подхода, если ваш стиль программирования ему соответствует и если область при¬ ложения его допускает. Но если в прошлом вы работали по-дру¬ гому, то данная методика, возможно, поначалу будет для вас непривычна. Прежде всего вам следует продумать план или архитектуру, которую ’ можно будет применять как каркас во многих после¬ дующих программных разработках. При разработке программ начинайте с этого каркаса. Модифицируйте его для конкретных приложений. Вы обнаружите, что при написании новых программ вам реже придется уподобляться фокуснику, вынимающему яркие ткани из воздуха; вместо этого вы будете брать детали старых программ, приспосабливать их и добавлять там, где необходимо, новые части. В той или иной степени так поступают все програм¬ мисты, но некоторые делают это более систематично, чем другие. Советую вам действовать крайне систематично, если только ваш характер и стиль программирования позволяют это. В качестве примера одного из способов построения вышеупо¬ мянутого каркаса опишем некоторую программу. Разные части этой программы выполняют разную работу. В дальнейшем я за¬ полню недостающие детали и приведу подпрограммы и прочие элементы программного текста, реализующие все компоненты модели. Модель изображена на рис. 3.5. Она подразделяется на три части: • процедуры настройки (строки 0—999); • подпрограммы (строки 1000—9999); • основную часть программы (строки 10000—65529). 70
ВХОДИМ В ПРОГРАММУ В ЭТОЙ ТОЧКЕ СТРОКИ 0-999 СТРОКИ 1000-9999 ПЕРЕХОД К СТРОКЕ 10000 Рис. 3.5. Обычно при построении программы ее разбивают на три основные части, показанные на настоящем рисунке. В начале программы размещают процедуры настройки и подпрограммы. Для ускорения доступа к подпрограммам строкам этой части программы присваиваются малые номера. Основная часть программы начинается в строке 10000 СТРОКИ 10-8999 СТРОКИ 9000-9999 СТРОКИ 10000-65529 ПЕРЕХОД К СТРОКЕ 9000 Рис. 3.6. Организация программы, альтернативная по¬ казанной на рис. 3.5. Здесь подпрограммы размещаются в самом начале программы, а процедуры настройки — после подпрограмм. При такой организации возможен более быстрый доступ к часто используемым подпрограм¬ мам В начале работы программы осуществляются процедуры на¬ стройки. Они подготавливают экран дисплея, задают размеры мас¬ сивов, определяют функции и выполняют другую аналогичную работу. 71
В последней строке процедур настройки содержится оператор GOTO 10000, который передает управление основной части про¬ граммы, пропуская подпрограммы. Для ускорения работы про¬ граммы подпрограммы размещаются в ее начале. Чем меньше но¬ мер строки, тем скорее интерпретатор Бейсика сможет ее найти и выполнить. В сущности, главные действия разворачиваются в основной части программы. Здесь сконцентрирована структура управления программой, отсюда начинаются цепочки вызовов подпрограмм и именно в этой части сосредоточен интеллект программы. Процеду¬ ры настройки составляют фундамент программы, а подпрограм¬ мы — это рабочие, приглашаемые для выполнения различных специальных работ. Но то, чем данная программа отличается от других, заключается именно в ее основной части. Как правило, из программы в программу переносится только то, что содержит¬ ся в процедурах настройки и подпрограммах. Большинство опытных программистов размещает часто ис¬ пользуемые подпрограммы в начале программ после процедур настройки. Некоторые предпочитают помещать подпрограммы в самом начале, организуя программу так, как изображено на рис. 3.6. Различие между этой организацией и организацией, пока¬ занной на рис. 3.5, заключается в перестановке местами подпро¬ грамм и процедур настройки. Это вполне удовлетворительная организация, но мне лично больше нравится та, что изображена на рис. 3.5, и я буду пользоваться ею в качестве модельной. Вернемся к рис. 3.5 и рассмотрим, что происходит внутри каждого из трех основных блоков программы. Процедуры настройки (строки 0—999). В начале работы про¬ грамма, как правило, должна выполнить инициализацию, кото¬ рая включает некоторые (а иногда и все) действия из следующего списка: • задание процедуры обработки ошибок; • очистку экрана монитора; • вывод на экран титульного листа программы; • нейтрализация некоторых клавиш, например комбинации CTRL-Break во избежание остановки программы при слу¬ чайном прикосновении к этим клавишам; • установку цвета рамки, фона и символов, выдаваемых на экран дисплея; • определение констант с помощью операторов присвоения и READ/DATA; • задание размеров массивов; • определе-ние функций; • получение от оператора необходимых параметров; • чтение файлов, необходимых для инициализации программы. Большинство из этих действий осуществлять в каждой про¬ грамме не обязательно, а в некоторых программах при настройке 72
0 REM гипотетическая процедура начальной настройки 1 REM SAVE "A:FIG3-7.BAS",А a ON ERROR GOTO 9600:REM включение процедуры обработки ошибок 5 0LS:REM очистить экран 10 REM Copyright 1984 by Henry Simpson I (C) 1984 Г. Симпсон 20 REM All Right Reserved ! все права сохраняются за автором. 30 REM 6/15/84 15.06.1984 40 GOSUB 9010:REM дезактивизация "опасных" клавиш 100 REM--Настройка дисплея-- 110 COLOR 7,0:REM установить цвета экрана 200 REM--Присвоение константам значений-- 210 С17.= 10 220 С2-. 5 230 С3#=. 333333432674406# 240 Сф="чеканные строки” 300 REM--Придание массивам размерности-- 310 DIM MONTH!(12):REM календарные месяцы 400 REM--Определение функций-- 410 DEF FNPLUS(А,В)=А+В 500 REM--Чтение 12-ти месяцев-- 510 DATA Янв, фвр,Март,Апр, Май, Июнь, Июль, Авг, Сен, Окт, Нбр, Дек 520 FOR А=1 ТО 12 530 READ MONTH!(А) 540 NEXT 600 REM—Оператор ввода "Input"-- 610 INPUT"Введите, пожалуйста, вашу фамилию: ";NAMES! 620 IF NAMES!="" GOTO 610 700 GOSUB 6200:REM чтение файла параметров настройки 990 GOTO 10000:REM переход к основной части программы Рис. 3.7. Типичные процедуры настройки, с помощью которых в начале ра¬ боты программы создается «титульный лист» на экране дисплея, отключа¬ ются клавиши останова и перезагрузки, определяются размеры массивов и выполняются прочие действия по настройке программы требуются действия, не включенные в данный список. Отметим, однако, что приведенные работы типичны для большинства программ. Вообще говоря, их порядок произволен, но некоторые шаги целесообразно выполнять в определенной последовательно¬ сти. Как правило, экран лучше всего очищать в самом начале ра¬ боты и тогда же следует установить цвета и вывести на экран титульный лист, если он есть. Это займет пользователя на неко¬ торое время и ему не будет казаться, что со стоящим перед ним с погасшим экраном компьютером происходит что-то неладное. Опасные клавиши надо отключить до начала приема данных от оператора. Размер массивов необходимо определить до того, как с помощью операторов READ или в процессе чтения файлов им будут присваиваться значения. Рис. 3.7 содержит листинг процедур настройки некоторой гипотетической программы. Этот программный текст выполняет все вышеописанные функции, а также содержит строку примеча¬ ний, которую можно использовать для сброса этой программы на диск (строка 1), заявление об авторских правах (строки 10—20) и дату составления (строка 30). Строка 1 содержит оператор SAVE, который идентифицирует программу и может быть использован для сброса ее на диск. Стро¬ ка 2 включает процедуру обработки ошибок (см. 10-й прием про¬ 73
граммирования). Строка 5 очищает экран. Строки 10 и 20 предуп¬ реждают об авторских правах. В строке 30 записана дата послед¬ него обновления программы. Строка 40 вызывает подпрограмму нейтрализации «опасных» клавиш типа комбинации Ctrl-Break (см. 8-й прием программирования). Строка 110 устанавливает цвета фона и символов, отобража¬ емых на экране (см. гл. 4). В строках 200—240 присваиваются значения константам. В строках 300—310 задаются размеры массивов. Строки 400—410 определяют функции. В строках 500—510 с помощью операторов DATA и READ константам при¬ сваиваются значения. В строках 600;—620 от пользователя прини¬ маются данные. В строке 700 вызывается подпрограмма, читаю¬ щая файл с данными для настройки. Строка 990 содержит опера¬ тор GOTO, передающий управление на строку 10000. Подпрограммы (строки 1000—9999). При размещении под¬ программ следует учитывать три основных фактора. Во-первых, диапазон строк, отведенных под подпрограммы, следует разбить на участки, выделяемые различным их категориям. В нашей мо¬ дели выделяются четыре категории подпрограмм (вывод, ввод, управление, файлы), а также всеобъемлющая пятая категория — «прочее». Во-вторых, число строк, выделяемых подпрограммам каждой категории, должно быть достаточным для их размещения. В-третьих, наиболее часто вызываемым подпрограммам, следует присваивать наименьшие номера строк. В нашей модели различным категориям подпрограмм выде¬ лены следующие диапазоны значений' • вывод : строки 1000—2999; • ввод строки 3000—3999; • управление : строки 4000—5999; • файлы : строки 6000—8999; • прочее:строки 9000—9999. В подпрограммах,приведенных в этой книге, номера строк при¬ своены в соответствии с данной схемой. Основная часть программы (строки 10000—65529). Эта часть программы размещается в ее конце и под нее отводится большое число строк. Общую модель этой части создать невозможно, поскольку ее содержание будет изменяться от программы к про¬ грамме. В основной части программы будут вызываться подпро¬ граммы выполнения соответствующих функции, а для управления ее работой будут использоваться жестко запрограммированная логика или вводимые пользователем команды. Предлагаемая организация модельной программы — всего лишь одна из многих возможных. В этой модели важно не то, сколько строк выделено под разные части программы, и даже не то, какие части в нее включены; важно лишь, что программа стро¬ ится по определенному плану, который легко описать и понять. В последующих разделах книги будут уточняться детали этого 74
плана в основном путем создания комплекта типовых подпро¬ грамм, которые войдут в соответствующую часть модельной программы. 6. СОЗДАЙТЕ БИБЛИОТЕКУ ПОДПРОГРАММ Если вы пишете программы, выполняющие близкие функции, то подпрограммы могут существенно облегчить вашу жизнь. Как только вы разработаете хорошую подпрограмму чтения по¬ следовательного файла1, стирания части экрана или формирова¬ ния меню, ваша работа существенно облегчится. Когда вам в следующий раз потребуется выполнить эту функцию, вы сможете обратиться к соответствующей подпрограмме, используя ее непо¬ средственно или с изменениями, и задача будет, решена. Это не только ускоряет дело, но и уменьшает количество ошибок. Дове¬ дите подпрограмму до совершенства и отладьте ее один раз, и вам больше никогда не потребуется делать это снова. 7. ДЛЯ ВЫПОЛНЕНИЯ ЛЮБЫХ РАБОТ СОЗДАВАЙТЕ ТИПОВЫЕ ПРОЦЕДУРЫ Создавать процедуры выполнения работ можно различными способами. Ниже приводятся четыре примера применения этого общего принципа. Пример 1. Используйте подпрограммы. Одна из основных причин использования подпрограмм (см. 6-й прием программи¬ рования) заключается в экономии усилий программиста. Вы бе¬ рете некоторую сложную функцию и упаковываете ее в подпро¬ грамму. В дальнейшем вас может не интересовать, что делается внутри вызываемой подпрограммы, и, вообще говоря, обращаясь к подпрограмме, вы не обязаны знать ее внутреннего устройства. Составив подпрограмму, вы свели выполнение сложной функции к простой процедуре вызова подпрограммы. Сведение сложных функций к вызову подпрограмм является частным случаем реализации общего принципа .создания типовых процедур. Следует постоянно стремиться к автоматизации про¬ граммирования и объединению различных работ в легко выпол¬ няемую процедуру. В этой главе уже приводилась простая, со¬ стоящая всего из одной строки процедура сброса программ на диск: I SAVE “PROGNAME.BAS“. А Это тоже пример создания процедуры. Она экономит время, уменьшает объем работы, требования к памяти и вероятность ошибки. Пример 2. Подготовка диска с программами. Вам следует под¬ готовить отформатизированные в нужном режиме диски, содержа¬ 1 Последовательные файлы и файлы прямого доступа рассматриваются в гл. 8. — Примеч. пер. 75
щие программы и прочие нужные при разработке программ фай¬ лы. Тогда вам не придется отвлекаться на переписывание вспо¬ могательных программ и файлов или менять диск, чтобы возвра¬ щаться в DOS. DOS можно записать на диск или не записывать — по ваше¬ му выбору. Конечно, DOS занимает место на диске, но все же луч¬ ше ее туда записать; тогда можно будет загружать систему и выполнять программу, не обращаясь к другим дискам, К тому же при этом вам не потребуется заменять рабочий диск на диск с DOS и обратно. Чтобы записать DOS на диск, форматизируйте его с параметром /S. Иначе говоря, дайте команду форматизации в виде FORMAT ск/5,где d — адрес дисковода, А или В. Загрузив DOS, вы получите доступ к ее резидентным коман¬ дам: COPY, DIR, ERASE, RENAME и TYPE. Но есть ряд команд DOS, которые можно выполнять, только имея на диске соответст¬ вующие файлы. Многие из этих команд, в частности DISKCOPY, DISKCOMP, COMP и EDLIN, полезны при разработке программ. Важно, чтобы на программном диске был записан интерпре¬ татор BASIC или BASICA. Если при программировании вы сочтете полезным переопре¬ делить функциональные клавиши, то вам следует составить и за¬ писать на диск программу на Бейсике с естественным именем, на¬ пример KEYS, которая быстро и легко это для вас сделает. Если вы хотите, чтобы некоторая программа (скажем, KEYS) выполнялась всякий раз, как вы загружаете DOS, то на ваших дисках следует иметь файл AUTOEXEC.BAT (см. ниже). Записывайте на диск все файлы, которыми вы часто пользуе¬ тесь при программировании. DOS и другие файлы занимают мес¬ то на программном диске и в некоторых случаях это может выз¬ вать осложнения. Очевидно, что если вам не хватает места на диске, то DOS или вспомогательные программы придется уда¬ лить. Но лучше иметь их на диске: это сэкономит вам время. Пример 3. Использование функциональных клавиш. Исполь¬ зуйте на полную мощность функциональные-клавиши своего ПК. Эти клавиши предназначены для хранения часто применяемых последовательностей вводимых с клавиатуры символов, что в свою очередь экономит время и труд при решении многих задач. Программы, использующие ПК для обработки текстов, обычно приписывают этим клавишам некоторые функции по редактиро¬ ванию текстов. Программы отображения графики обычно присва¬ ивают этим клавишам какие-то стандартные функции манипули¬ рования графикой. При программировании этим клавишам сле¬ дует присвоить функции, обычные при разработке программ. В системе Бейсик ПК фирмы IBM десяти функциональным клави¬ шам приписаны следующие функции: Fl—LIST F2—RUN + клавиша «Ввод» F3—LOAD” 76
F4—SAVE” F5—CONT-Fклавиша «Ввод» F6—,”LPT1:” F7—TRON + клавиша «Ввод» F8—TROFF4-клавиша «Ввод» F9—KEY F10—SCREEN 0, 0, 04-клавиша «Ввод» Возможно, что при разработке программ вы пожелаете из¬ менить эти определения. Оптимальное определение функциональ¬ ных клавиш зависит от типа выполняемый вами задачи, вашего стиля программирования, а также этапа разработки программы. По-видимому, не существует определения функциональных кла¬ виш, идеально устраивающего всех программистов и подходя¬ щих для любых задач, но вы наверняка сможете улучшить опре¬ деления, заданные разработчиком интерпретатора1. Лично я предпочитаю следующее .определение функций: F1—CLS.LIST. Я склонен очищать экран до просмотра текста и поэтому изменил определение клавиши F1 на очистку экрана с последующим просмотром программы. F2—F4. Определений этих клавиш я не менял. F5—EDIT. Вывод на экран строки перед ее редактированием. F6—FILES 4-клавиша «Ввод». Сообщает, какие файлы на¬ ходятся на диске со стандартным адресом. F7—DELETE. Облегчает удаление одной или нескольких строк при редактировании программы. F8—REM. Соответствует тому значению, которое придается в данной книге использованию примечаний в программах. Я скло¬ нен вносить в программы множество операторов REM. F9—LIST 14-клавиша «Ввод»4-два раза клавиша «Курсор вверх» 4-пять пробелов. Нажмите эту клавишу — высветится строка 1 вашей программы. Затем курсор переместится вверх и забьет пробелами номер строки и слово REM,давая вам возмож¬ ность сбросить программу на диск простым нажатием на клавишу «Ввод», конечно, при условии, что строка 1 вашей программы дей¬ ствительно содержит описанный ранее комментарий с оператором SAVE в тексте. F10—CLS 4-клавиша «Ввод». Просто очищает экран. Эти и подобные им определения функциональных клавиш выполняются с помощью оператора KEY. Этот оператор имеет синтаксис KEYn, текст определения $ , где п — номер функцио¬ нальной клавиши, а текст определения £ — строка1 2 приписыва¬ 1 Интерпретатор BASIC — программа, которая выполняет вашу программу,- написанную на языке Бейсик.—Примеч. пер. 2 В программировании термин «строка» имеет, по крайней мере, три разных значения, которым соответствуют такие английские эквиваленты: a) string — строка, т. е. последовательность символов; б) line — строка текста (программы, распечатки, книги и т. п.); в) row — строка таблицы, строка экрана. Как правило, смысл термина будет ясен из контекста, например «строка 1000 программы вы¬ водит строку символов А$ по центру строки 10 экрана».—Примеч. пер. 77
емых этой клавише символов (0—15 знаков). Такое определение можно выполнять как непосредственно с клавиатуры (но это мы вам не советуем), так и написав программу на Бейсике, которая будет делать это за вас. Имея такую программу, вы можете вы¬ полнять ее при входе в Бейсик или иметь файл AUTOEXEC.BAT, который будет выполнять эту программу при загрузке системы.’ Для определения функциональных клавиш с клавиатуры на¬ берите слово KEY, номер определяемой клавиши и назначаемую ей строку. Чтобы, например, присвоить клавише F5 значение EDIT, наберите следующее предложение: KEY 5,” EDIT ” Обратите внимание на пробел, следующий за словом EDIT. Он позволяет программисту набирать номер строки программы, не нажимая сперва на клавишу пробела. Если вы хотите включить в строку специальный символ, на¬ пример клавишу «Ввод», знак кавычки или клавишу курсора, то следует сцепить функцию CHR$ шифра этого символа в коде ASCII (см. приложение В) с заключенными в кавычки знаками. Например, чтобы клавиша F2 не только высвечивала команду RUN, но и вводила ее, вы должны воспользоваться таким опера¬ тором: KEY 2, ”RUN” + CHR$(13) Чтобы клавиша F3 высвечивала команду LOAD, за которой сле¬ дует одиночная кавычка, воспользуйтесь следующим оператором: KEY 3, ’’LIST” + CHR$(34) Чтобы клавиша F9 выдавала команду LIST 1,за которой следуют два раза клавиши «Курсор вверх», воспользуйтесь таким опера¬ тором: KEY 9, ’’LIST l”+CHR$(30)+CHR$(30) На рис. 3.8 приведен листинг программы, которой можно вос¬ пользоваться для выполнения только что описанных определений функциональных клавиш. Набирать всякий раз с клавиатуры оп¬ ределения всех этих клавиш слишком сложно. Намного проще написать маленькую программу, которая будет выполнять все приведенные операции. Строка 1 содержит примечание с операто¬ ром SAVE типа описанных выше. В строках 10, 20 и 30 строковым переменным ENTERS, QUOTE$ и UP$ присваиваются соответ¬ ственно значения «Ввод», одиночный знак кавычки и «Курсор вверх». В строках 40—130 определяются функциональные кла¬ виши. Назначение строк 140—170 не столь очевидно. Строка 140 включает выдачу на 25-ю строку экрана определений функцио¬ нальных клавиш. Это необходимо при вызове данной программы 78
1 REM SAVE "A:KEYS. BAS",A 10 ENTERS=CHRS(13):REM клавиша "Ввод" 20 QUOTES:CHR$(34):REM кавычки 30 UP$-CHR$(30):REM клавиша "Курсор вверх" 40 KEY 1, "CLS:LIST " 50 KEY 2, "RUN"CENTERS 60 KEY 3, "LOAD"+QUOTES 70 KEY 4, "SAVE"+QUOTES 60 KEY 5) "EDIT " 90. KEY 6, "FILES"+ENTERS 100 KEY 7, "DELETE " 110 KEY 6, "REM " 120 KEY 9, "LIST 1"+ENTERS + UPS+U₽S+" ” 130 KEY 10, "CLS"+ENTERS 140 KEY ON 150 CLS 160 FILES 170 NEW Рис. 3.8. Программа определения функциональ¬ ных клавиш из файла AUTOEXEC.BAT при инициализации системы, посколь¬ ку DOS не включает строку 25 автоматически. Строка 150 очища¬ ет экран; Строка 160 выдает на экран оглавление диска. Строка 170 удаляет программу определения функциональных клавиш из памяти, очищая тем самым место для следующей программы. Эта строка делает с программой то же самое, что причиняет самому себе путешественник во времени, случайно убивающий собственного пра-пра-прадеду.шку: уничтожает ее и тем самым саму себя. Если вы введете данную программу, то прежде, чем запустить, обязательно сбросьте ее на диск. Как уже отмечалось, часто оказывается удобным, чтобы ком¬ пьютер присваивал функциональным клавишам значения при ини¬ циализации системы. Для этого вам надо создать файл AUTOEXEC.BAT. То же самое необходимо и при создании систем «под ключ», описываемых в параграфе «9-й прием программиро¬ вания» данной главы. Пример 4. Применение пакетных файлов. Пакетным файлом называется текстовый файл, содержащий команды DOS. Когда, находясь в DOS, набирают имя этого файла и нажимают клавишу «Ввод», содержащиеся в этом файле команды выполняются. Если, например, пакетный файл по имени DING.BAT содержит команду BASICA, то при наборе слова DING и нажатии на клавишу «Ввод» выполнится команда, содержащаяся в файле, и загрузится интер¬ претатор BASICA, как будто вы набрали с клавиатуры команду BASICA. Но с помощью таких файлов в силу того, что они могут содер¬ жать много команд, можно делать и гораздо более интересные ве¬ щи. Рассмотрим, к примеру, что может делать такой пакетный файл: 79
CLS DATE TIME SORT < DATA1.TXT > DATA1.TXT COPY DATA1 B:DATA1 BASICA PROG.BAS Этот файл очистит экран, затребует дату и время, отсортирует файл по имени DATA1.TXT, скопирует его на диск, вставленный в дисковод В, вызовет BASICA и запустит программу по имени PROG.BAS. Хотя выполнение этой конкретной последовательно¬ сти команд имеет весьма ограниченное применение, использова¬ ние пакетных файлов для «консервирования» определенных часто повторяющихся последовательностей команд DOS имеет очень большое значение. Пакетные файлы позволяют упаковы¬ вать такие последовательности команд в простую, пригодную к использованию форму, т. е. в виде процедур. Чаще всего применяются два способа создания пакетных файлов: с помощью команды COPY CON и с помощью редактора текстов, например EDLIN. Если вы не собираетесь создавать очень длинный текстовый файл, то команды COPY CON вполне достаточно. К тому же она намного проще и быстрее в работе, чем EDLIN. Далее кратко описывается процесс создания пакет¬ ного файла командой COPY CON. EDLIN описан в вашем руко¬ водстве по DOS, и если вам это интересно, то обратитесь к этому руководству. На самом деле EDLIN не столь сложен, как кажется при чтении документации фирмы IBM или обычных журнальных статей. Большинство программистов может если не овладеть этим редактором в совершенстве, то по крайней мере научиться его эффективно использовать менее чем за час. Давайте приступим сразу к конкретной задаче, а именно к созданию пакетного файла, который очистит экран, примет дату, загрузит BASICA и выполнит программу по имени FIRST.BAS. Назовем этот файл WOM.BAT. Процедура его создания будет состоять из следующих шагов: • Наберите команду COPY CON, за которой следует двоеточие и имя пакетного файла, например: COPY CON:WOM.BAT • Нажмите клавишу «Ввод». Тогда подсказка DOS вида А> исчезнет, а в следующей строке экрана появится кур¬ сор подчеркивание ( ). Это означает, что ПК готов к при¬ ему содержимого файла. • Наберите каждую команду DOS, нажимая после нее кла¬ вишу «Ввод». Например: CLS нажмите клавишу «Ввод» DATE нажмите клавишу «Ввод» BASICA FIRST.BAS нажмите клавишу «Ввод» 80
Если при вводе вы сделаете ошибку, то нажмите на комбина¬ цию клавиш Ctrl-C и прекратите ввод. Начните все сначала: COPY CON легко пользоваться, но, в отличие от редакторов тек¬ ста, эта команда не позволяет редактировать вводимые данные. • Если вы все ввели правильно, то нажмите на клавишу F6 или комбинацию Ctrl-Z. После этого ПК запишет ваш па¬ кетный файл. Вы можете проверить содержимое этого файла, набрав ТУРЕ имя-файла (например, TYPE WOM.BAT). Просмотреть файл можно также и с помощью редактора текстов. Хотя все наиболее существенное уже было сказано, приведем несколько команд DOS, которые, возможно, вы захотите включить в пакетные файлы, чтобы придать им больший блеск: ECHO — эта команда выдает на экран любые следующие за ней знаки. Является эквивалентом в DOS оператора PRINT языка Бейсик. Применяется, когда при выполнении пакетного файла вы хотите что-нибудь сообщить оператору. ECHO OFF —эта команда отключает вывод на экран команд DOS из пакетного файла. Если ваш пакетный файл содержит много команд DOS, то они будут выводиться на экран по мере их выполнения и сдвигать содержимое экрана вверх, а это, во-пер¬ вых, некрасиво, а во-вторых, может создать впечатление, что ПК работает по собственной инициативе. В подобных случаях желательно отключить эхо. PAUSE — эта команда заставляет ПК делать паузу и выда¬ вать указание: «Strike any key when ready...» («нажмите любую клавишу, когда будете готовы...»). После нажатия на клавишу работа продолжится. IF— как и оператор IF в- Бейсике, команда IF позволяет принимать решения во время выполнения пакетного файла. Кроме того, вы можете поручить пользователю вводить не¬ которые значения, заданные в пакетных файлах в параметри¬ ческой форме. Подробности можно найти в вашем руководстве по DOS. Возможно, что после весьма продолжительного обсуждения того, как сбрасывать программы на диск, подготавливать диски к работе, пользоваться функциональными клавишами и создавать пакетные файлы некоторые читатели забудут, что эти конкретные примеры были приведены для иллюстрации более фундаменталь¬ ного положения о целесообразности создания процедур. Никогда не забывайте об этом общем принципе, приложимом к большинст¬ ву аспектов программирования: вы всегда должны искать возмож¬ ность создавать процедуры. Как уже отмечалось, цель создания процедур состоит в упрощении вашей работы и уменьшении числа ошибок. 81
8. ОСТЕРЕГАЙТЕСЬ «ОПАСНЫХ» СОЧЕТАНИЙ КЛАВИШ Есть три опасных сочетания клавиш, которые могут прервать выполнение программ на BASI.Ce. Перечислим эти комбинации: • Ctrl-Alt-Del. Эта комбинация вызывает рестарт1 системы, как будто компьютер был выключен и включен снова ; • Ctrl-C. В некоторых случаях эта комбинация прерывает работу программы; • Ctrl-Break. Эта комбинация обычно прерывает работу про¬ граммы. Приведенные сочетания клавиш предназначены для того, чтобы пользователь мог остановить выполняющуюся в данный момент программу и перейти к другой работе. Так как в каждом случае требуется, чтобы одновременно были нажаты несколько клавиш, эти комбинации содержат элемент безопасности. Мало¬ вероятно, чтобы пользователь случайно нажал одновременно две соответствующие клавиши. Однако бывает желательно нейтрализовать некоторые из таких комбинаций и тем самым предотвратить последствия не только случайного, но и умышленного их нажатия. Например, нежела¬ тельно прерывание пользователем работы программы во время записи в файл в тех случаях, когда оно может вызвать потерю данных, а также во многих других ситуациях. Какие клавиши следует нейтрализовать и когда их следует активизировать снова, определяется требованиями конкретной программы, и решать это должны вы сами. Далее описывается, как с помощью простых подпрограмм это можно сделать. Отталкиваясь от приведенных описаний примеров, вы сможете адаптировать эти подпрограммы в соответствии со своими потребностями. Как вам, наверное, известно, существуют клавиши, сигнал которых трудно перехватить обычным способом. Сигнал любой клавиши, которой соответствует некоторый шифр в коде ASCII, легко перехватить с помощью обычного оператора IF-THEN. Так, если вы хотите предотвратить использование знаков амперсенд (&) в вводимых данных, то примените такие операторы: 10000 A$=INKEY$:IF А$= " ” GOTO 10000 10010 IF А$=”&” GOTO 10000 Строка 10010 ищет нежелательный символ, а, обнаружив его, передает управление обратно на предыдущую строку. Этот цикл будет выполняться до тех пор, пока пользователь не нажмет на другую клавишу. К сожалению, этот прием неприменим к трем интересующим нас комбинациям, а также к некоторым другим, поскольку им не 1 Под рестартом понимается сброс процессора и внешних устройств, очистка памяти и повторная загрузка DOS.—Примеч. пер. 82
соответствует никакой распознаваемый символ и они не имеют шифра в коде ASCII. Вы, например, не найдете в приложении В шифр кода ASCII для сочетания Ctrl-Break. Но есть другой спо¬ соб перехвата сигнала клавиш: с помощью операторов KEY, KEY(n), ON и ON KEY(n). Вы можете воспользоваться им, если располагаете усовершенствованным интерпретатором BAS1CA (он не будет работать со стандартным дисковым интерпретатором Бейсик). Этот способ не был описан в первом издании руководст¬ ва по Бейсику фирмы IBM, хотя, как ни странно, был документи¬ рован в руководстве по Бейсику для компьютера PCjr. Для перехвата сигналов вместо кодов ASCII или символов вам следует применить коды сканирования. Коды сканирования клавиатуры ПК фирмы IBM изображены на рис. 3.9 слева от кла¬ виш. Например, код сканирования клавиши Scroll Lock/Break имеет значение 70, код сканирования клавиши С —46, а клавиши Del — 83. Код сканирования — это код, порождаемый при нажа¬ тии на клавишу внутри клавиатуры и посылаемый в системный блок. Затем системный блок интерпретирует этот код, преобра¬ зуя его в значение кода ASCII или в сигнал, означающий, что эта клавиша требует специальной обработки. Отметим еще раз, что три рассматриваемые комбинации клавиш требуют особого обращения, так как они вызывают прерывание работы ПК. С помощью кодов сканирования сигналы от клавиш можно перехватить раньше, чем они смогут прервать работу ПК. Для подготовки программного текста, осуществляющего такой пере¬ хват, и его активизации следует выполнить такие действия. • Загрузите интерпретатор BASICA. • Выберите комбинацию клавиш, сигнал которой вы хотите перехватить. Мы будем рассматривать следующие три ком¬ бинации: Ctrl4- Alt -(-Del (3 клавиши); Ctrl-j-C (2 клавиши); Ctrl-|-Scroll Lock/Break (2 клавиши). • Определите код регистра. Клавиатура ПК имеет три регист¬ ра, которым соответствуют такие коды: нижний регистр (строчные буквы) — 0, верхний регистр (большие буквы, регистр Shift) — 1, регистр Ctrl — 4, регистр Alt — 8. При одновременном использовании нескольких регистров (на¬ пример, Ctrl + Alt) код комбинации равен сумме кодов индивиду¬ альных регистров. Например, код комбинированного регистра, соответствующего одновременно нажатым клавишам Ctrl и Alt, равен 12, а клавишам Shift и Ctrl — пяти. • Определите код сканирования последней из нажатых кла¬ виш. Как отмечалось ранее, коды сканирования интересу¬ ющих нас клавиш равны соответственно 70, 46 и 83. 83
Рис. 3.9. Схема клавиатуры ПК фирмы IBM с кодами сканирования; любезно предоставлена фирмой IBM 84
• Воспользовавшись фиктивными функциональными клавишами с номерами 15—20, подготовьте одну или несколько процедур перехвата сигнала комбинации клавиш. Соответствие между фиктивной функциональной клавишей и перехва i ываемой комбинацией устанавливается с помощью оператора KEY. Этот оператор имеет следующий формат: KEY п, CHR$ (код регистра) -|-CHR$ (код сканирования) Например, оператор перехвата сигнала от комбинации клавиш Ctrl — С будет выглядеть следующим образом: KEY 15, CHR$(4) +CHR$(46) Приведем еще несколько примеров. • Перехват сигнала клавиши «а»: KEY 15, CHR$(0) + + CHR$(30). • Перехват сигнала клавиши «А»: KEY 15, CHR$(1) + + CHR$(30). • Перехват сигнала комбинации Alt—A: KEY 15, CHR$(8) + + CHR$(30). • Перехват сигнала комбинации Ctrl—A: KEY 15, CHR$(4) + + CHR$(30). • Перехват сигнала комбинации Ctrl—Alt—Del: KEY 15, CHR$(12) +CHR$(83). • Для активизации перехвата добавьте операторы ON KEY (п) и KEY (n) ON. Например, для активизации перехвата сигналов клавиши «А» вставьте после оператора KEY два следующих оператора: ON KEY(15) GOSUB номер строки KEY(15) ON На рис. 3.10 приведен листинг подпрограммы, которая нейт¬ рализует в соответствии с только что изложенной процедурой три «опасные» комбинации клавиш. В строках 9010, 9020 и 9030 содержатся операторы KEY. Строки 9040, 9050 и 9060 содержат 0 REM Подпрограмма дезактивизации "опасных" клавиш 1 REM SAVE"A:FIG3-10" , А 9000 REM--Дезактивизировать "опасные" клавиши-- 9010 KEY 15, CHR$(12)+CHR$(83):REM Ctrl Alt Del 9020 KEY 16, CHR$(4)+CHRi(46) :REM Ctrl C 9030 KEY 17, CHR$(4)+CHR$(70):REM Ctrl Break 9040 ON KEY (15) GOSUB 9080:KEY(15) ON 9050 ON KEY (16) GOSUB 9080:KEY(16) ON 9060 ON KEY (17) GOSUB 9080:KEY(17) ON 9070 RETURN 9080 BEEP 9090 RETURN Рис. 3.10. Распечатка подпрограммы, нейтрализующей «опасные» сочетания клавиш 85
операторы включения перехвата ON KEY(п) и KEY(n)ON. В каж¬ дой из трех последних строк имеется оператор GOSUB, вызыва¬ ющий подпрограмму, которая начинается в строке 9080. Эта под¬ программа всего лишь выдает на динамик звуковой сигнал, но вы можете написать подпрограмму, которая будет делать то, что тре¬ буется в вашей программе. Например, с помощью подпрограммы, состоящей из одного оператора RETURN, программа может про¬ сто игнорировать перехваченные сигналы. Вы можете подгото¬ вить подпрограмму выдачи сообщений об ошибках. Для возврата управления из подпрограммы в определенную часть программы, например в главное меню, можно воспользоваться форматом RETURN номер строки (например, RETURN 10000). В таком случае поступавший от клавиш сигнал приведет к выходу из вы¬ полняющейся части программы. Но при осуществлении таких нестандартных возвратов вам следует соблюдать осторожность, поскольку незавершенные операторы GOSUB, FOR и WHILE остаются активными и, как неоплаченные счета, могут в даль¬ нейшем вызвать неприятности. Возможно, что при выполнении программы вам потребуется отменить перехват сигнала о нажатии на такие клавиши. Это намного проще, чем запустить процедуру перехвата. Для этого вам достаточно выполнить оператор KEY(n)OFF. На рис. 3.11 изображена подпрограмма, отменяющая перехват сигналов трех комбинаций клавиш, который выполняется подпрограммой, изо¬ браженной на рис. 3.10. После того как подпрограмма отработает, нажатие этих клавиш будет оказывать на работу программы обычное действие. До того как использовать эти подпрограммы, желательно опробовать их работу. Это можно сделать, составив короткую программу, включающую обе подпрограммы, цикл INKEY$ и некоторый механизм вызова подпрограмм по вашему выбору. Указанную работу (совместно с вышеприведенными подпрограм¬ мами) выполнят такие строки: 10 REM Программа, демонстрирующая работу оператора KEY 20 A$=INKEY$ 30 IF A£=”D” THEN GOSUB 9000:REM отключаем «опасные» клавиши 40 IF A$= ”A” THEN GOSUB 9100:REM включаем «опасные» клавиши 50 GOTO 30 0 REM Подпрограмма реактивизации "опасных" клавиш 1 REM SAVE"A:FIG3-11", А 9100 REM--Активизировать "опасные” клавиши-- 9110 KEY (15) OFF 9120 KEY (16) OFF 9130 KEY (17) OFF 9140 RETURN Рис. 3.11. Распечатка подпрограммы, активизирующей «опасные» клавиши, выключенные подпрограммой, изо¬ браженной на рис. 3.10 86
Ввод буквы «D» при выполнении этой программы нейтрализу¬ ет опасные клавиши, а ввод буквы «А» активизирует их вновь. Перед прогоном этой программы сбросьте ее на диск, так как на¬ жатие клавиш Ctrl—Alt—Del в режиме «А» вызовет рестарт системы и сотрет программу из памяти. Если вы решите включить в свою программу нейтрализацию, то проверьте соответствующий программный текст, но не поме¬ щайте его в программу до конца разработки, так как в противном случае вы не сможете остановить работу своей программы, если вам это потребуется. Но как одновременно включить и не вклю¬ чить в программу некоторую процедуру? Для этого проще всего реализовать ее как подпрограмму (см. рис. 3.10), а затем преоб¬ разовать вызов этой подпрограммы в оператор примечания, как это показано в следующем примере: 40 REM GOSUB 9010.-REM отключение «опасных» клавиш. На время разработки программы оставьте оператор REM в этой строке, а когда разработка будет закончена, удалите; тогда вызов подпрограммы будет функционировать нормально. 9. СТРОЙТЕ СИСТЕМУ «ПОД КЛЮЧ» Системой «под ключ» называется система, правильно рабо тающая при минимальном вмешательстве оператора. Для поль¬ зователей системы «под ключ» обычно проектируются таким об¬ разом, чтобы им не приходилось взаимодействовать с программой на уровне DOS или языка Бейсик. Пользователь работает с по¬ нятной ему и мало подверженной ошибкам «программой», кото¬ рая с точки зрения специалиста, возможно, является не програм¬ мой, а целой системой. Для запуска систем «под ключ» от оператора требуется только включить или перезагрузить компьютер. Как только ПК оживает, он сам автоматически загружает DOS, Бейсик, а затем запускает программу. Кроме того, такая система позволяет пользователю легко переходить от одних программ к другим, так как они объе¬ динены в пакет, и для выхода из одной программы и запуска следующей не требуется возврата в Бейсик. Замена дисков сво¬ дится к необходимому минимуму, а если без нее невозможно обойтись, то пользователю даются подробные указания о том, как это сделать. Система должна обеспечивать все возможное для минимизации труда пользователя и количества принимаемых им решений. Хотя обычно системы «под ключ» считают нужными подго¬ тавливать только для новичков, иногда они оказываются полез¬ ными и квалифицированным пользователям. Например, им приго¬ дятся рабочие программные диски, содержащие программу оп¬ ределения функциональных клавиш, автоматически выполняемую 87
при включении компьютера (см. 7-й прием программирования). На самом деле эта программа выполняет три действия: определяет функциональные клавиши, очищает экран и выводит оглавление диска. При запуске этой программы из файла AUTOEXEC.BAT попутно загружается интерпретатор BASIC или BASICA. Файл AUTOEXEC.BAT — это специальный пакетный файл, со¬ держащий команды DOS. При включении и перезагрузке компью¬ тера DOS ищет на диске файл с таким именем и, если находит, выполняет содержащиеся в нем команды. Если этот файл отсут¬ ствует на диске, то выполняется обычная процедура запроса даты и времени и вывода подсказки DOS вида А>. Если на диске есть такой файл, то можно пропустить эту процедуру и за¬ ставить DOS вызвать Бейсик и автоматически запустить нужную программу. Если в файле AUTOEXEC.BAT содержатся команды DATE или TIME, то будут затребованы дата или время или и то и другое. Такой файл может выполнить любую команду DOS. Очевидно, что в этом заключается ключ к созданию систем, в которых ваша программа будет автоматически вызываться при включении компьютера. Файл AUTOEXEC.BAT создается точно так же, как и любой другой пакетный файл, единственное различие состоит в присваи¬ ваемом ему имени. Содержимое этого файла зависит от того, что должно делаться при включении ПК. Если, например, вам надо, чтобы этот файл вызывал Бейсик, а затем выполнял про¬ грамму на этом языке, то файл должен содержать команду BASIC, за которой следует имя программы, например BASIC BUDGET.BAS. Если вам надо, чтобы запрашивались дата и время, то до команды BASIC файл должен содержать команды DATE и TIME. Иначе говоря, строки файла AUTOEXEC.BAT будут выглядеть следующим образом: DATE TIME BASIC BUDGET.BAS Как и любой пакетный файл, AUTOEXEC.BAT можно создать либо с помощью команды COPY CON, либо с помощью редактора текстов, например EDLIN (см. 8-й прием программирования). 10. ОБРАБАТЫВАЙТЕ ОШИБКИ Во время работы программы могут возникать многообразные ошибки. В зависимости от того, кто в них повинен, их можно разбить на три категории: • ошибки ПК. Например, случилась неполадка в оборудова¬ нии; • ошибки программиста. Например, в тексте оставлена син¬ таксическая ошибка; 88
• ошибки оператора. Например, он пытается печатать отчет, когда в принтере кончилась бумага. Ошибки первого рода исключительно редки и обычно ими можно пренебречь. В отличие от людей — программистов и опе¬ раторов — ПК почти не совершает ошибок. Это может быть обид¬ ным для людей, но такова действительность. Ошибки второго рода встречаются чаще. При разработке любых программ ошибки неизбежны, и программист постепенно обучается с ними работать. Работать с ошибками вовсе не значит с ними сосуществовать (т. е. выносить их присутствие). Это всего лишь означает, что надо уметь предвидеть ошибки и систе¬ матически их устранять. Прежде чем передать программу оператору, программист дол¬ жен быть уверен, что ее текст свободен от ошибок. Вероятность того, что программа действительно свободна от ошибок, зави¬ сит от ряда факторов. Три наиболее важных фактора — квали¬ фикация программиста, сложность программы и количество вре¬ мени, затраченного на ее тестирование. Ни один программист не может гарантировать, что программа полностью свободна от ошибок: они могут встречаться и действительно встречаются. Ошибки третьего типа, т. е. ошибки оператора, случаются чаще остальных. Ошибки делает даже самый опытный пользова¬ тель. Например, он может оставить открытой дверцу дисковода, вставить в него не ту дискету или забыть включить принтер. Коды ошибок перечислены в приложении А к данной книге. Подробнее они описаны в приложении А к руководству по языку BASIC фирмы IBM. Каждая ошибка прекращает работу програм¬ мы. Это может очень раздосадовать пользователя, особенно если он потратил много времени на ввод данных или другую работу, которая в таком случае пропадет даром. Во время разработки программы с той же проблемой иногда сталкиваются и програм¬ мисты. Отладку программ можно сравнить с прогулкой по мин¬ ному полю. Вам может понадобиться разминировать некоторый участок минного поля, не взлетев на воздух по дороге к нему. Иначе говоря, для исправления одних ошибок вам может потребо¬ ваться временно игнорировать другие. Поэтому в программы следует включать процедуры обработки ошибок. Такие процедуры сообщают оператору, что создалась ошибочная ситуация, описывают эту ситуацию и, возможно, вы¬ полняют другие действия (например, сообщают номер телефона программиста). Более существенно, что они предотвращают ава¬ рийную остановку программы, позволяя закончить работу. Ключом к обработке ошибок является оператор ON ERROR GOTO. За этим оператором следует номер строки, в которой начи¬ нается процедура обработки ошибок. Как правило, этот оператор помещают в самое начало программы. Пусть, например, располо¬ 89
женный в строке 2 оператор должен обрабатывать ошибки с по¬ мощью процедуры, начинающейся в строке 9800: 2 ON ERROR GOTO 9800 Сама процедура обработки ошибок может быть и очень про¬ стой, и весьма сложной. Как минимум она должна содержать оператор RESUME. Этот оператор позволяет продолжить выпол¬ нение программы после того, как произошла ошибка. Если за словом RESUME следует номер строки, то работа программы продолжится с этой строки. К сожалению, не существует просто¬ го правила, позволяющего определить, каким из трех форм опера¬ тора RESUME следует воспользоваться в каждом конкретном случае. Ниже приведена, пожалуй, самая простая процедура обработ¬ ки ошибок: 9800 RESUME Эта процедура лишь перехватывает ошибки, заставляя программу продолжить работу с того места, где эта ошибка произошла. Она не предупреждает пользователя об ошибке и не распознает ее вид. Поместить в свою программу такую процедуру — все равно, что замести пыль под ковер: так можно только скрыть проблему, но не распознать и не устранить. Чтобы ошибку можно было исправить, ее прежде всего следует идентифицировать. При встрече с ошибкой BASIC присваивает переменной ERR значение кода ошибки, а в переменную ERL помещает номер строки программы, в которой встретилась эта ошибка. Благодаря этому легко написать оператор, выводящий информацию об ошибке, например: 9800 REM — Процедура обработки ошибок — 9810 PRINT ’’Код oluh6kh”;ERR; ”в строке”; ERL 9820 RESUME Эта процедура выведет информацию об ошибке в той позиции экрана, где окажется курсор, а затем продолжит выполнение программы. Хотя эта процедура и может вполне устроить программистов, она имеет два недостатка: во-первых, в ней не выводится назва¬ ние ошибки, а только сообщается ее код, который еще придется искать в руководстве по языку Бейсик, а во-вторых, она не при¬ останавливает работу программы. Полноценная процедура об¬ работки ошибок, как правило, должна обеспечивать обе эти возможности. Для идентификации ошибок процедура обработки должна свя¬ зать код ошибки ERR с соответствующим сообщением, приве денным в приложении А к данной книге и в руководстве по языку Бейсик. Иначе говоря, вы можете поручить своей процедуре 90
проверку кодов ERR и вывод соответствующих сообщений об ошибках. Этот метод иллюстрируется следующим программным текстом: 9912 IF ERR = 53 THEN PRINT’’Файл не найден” 9914 IF ERR = 58 THEN PRINT’’Файл уже существует” Однако составить такую процедуру не так уж просто. Основ¬ ная сложность проистекает из многочисленности кодов ошибок (попробуйте их сосчитать!) и соответствующих им сообщений: их слишком много для включения в одну процедуру. Чтобы свести этот список к более обозримому, необходимо что-то придумать. Возможность сжатия основана на факте существования трех кате¬ горий ошибок: ошибок ПК, программиста и оператора. Об этом уже говорилось в данном параграфе. При этом отмечалось, что ошибки ПК редки, а ошибки программиста должны быть редки, тогда как ошибки оператора встречаются довольно часто. Итак, идея заключается в том, чтобы процедуре обработки ошибок по¬ ручить подготовку детальных сведений об ошибках оператора и кратких сообщений об ошибках прочих типов. Такая тактика оказывается успешной, поскольку имеется не более десятка ко¬ дов, относящихся к ошибкам оператора. Эти ошибки преиму¬ щественно связаны с дисками, принтером и прочим оборудова¬ нием, за правильной работой которого обычно следит оператор. Более сложная процедура. Посмотрим теперь, как объединить все эти компоненты в более сложную процедуру обработки оши¬ бок. На рис. 3.12 изображен листинг процедуры, которая выпол¬ няет следующую работу: • очищает экран; е привлекает внимание оператора; • выдает на дисплей код ошибки и номер строки; $ выдает сообщение об ошибке; е приостанавливает работу программы, пока не будет нажата клавиша «Пробел»; е продолжает работу программы, начиная со строки 10000. Подпрограмма, расположенная в строках 4010—4080, не вхо¬ дит в процедуру обработки ошибок, но используется ею. Эта про¬ грамма приостанавливает работу программы до тех пор, пока не будет нажата клавиша «Пробел». Строка 4020 перемещает курсор в строку 23, столбец 17 (нижнюю часть экрана). Строка 4030 переключает вывод на дисплей в режим инвертированного отобра¬ жения (темные символы на светлом фоне). Строка 4040 выводит сообщение «Для продолжения работы нажмите клавишу пробела» по центру строки 23 экрана. Строка 4050 переключает дисплей обратно в режим нормального отображения. Строка 4060 содер¬ жит цикл INKEY$, выполняющийся до тех пор, пока не будет нажата клавиша «Пробел». 91
0 REM Процедура обработки ошибок (полный экран) 1 REM SAVE"A:FIG3-12" , А 4010 REM--Подпрограмма паузы-* 4020 LOCATE 23,WIDEZ/2-23 4030 COLOR 16, 7:REM режим мигающего инвертированного отображения 4040 PRINT"[Для продолжения работы нажмите клавишу пробела]"; 4050 COLOR 7,0:REM режим нормального отображения 4060 A|:INKEY|:IF А|<>" " GOTO 4060 4070 PRINT 4080 RETURN 9800 REM--Процедура обработки ошибок (полный экран)-- 9804 REM •!I ВНИМАНИЕ •1! 9805 REM если вы работаете с 40-столбцовым дисплеем, то в каждом операторе 9806 REM LOCATE из второго аргумента следует вычесть число 20 9810 ВЕЕР 9820 CLS 98 30 LOCATE 6, 33 9840 COLOR 0,7:REM инверсия 9850 PRINT "ОШИБОЧНАЯ СИТУАЦИЯ" 9860 COLOR 7,0:REM нормальное отображение 9870 LOCATE 10,30 9880 PRINT"KOfl ОШИБКИ номер ";ERR 9890 LOCATE 12,30 9900 PRINT"CTPOKA ПРОГРАММЫ номер ";ERL 9910 Е|="Ошибка в программе или в файле" 9912 IF ERR=53 THEN Е|="файл не найден" 9914 IF ERR-58 THEN Е|="файл уже существует" 9916 IF ERR=61 THEN Е|:"На диске не осталось места" 9918 IF ERR=70 THEN Е|="Диск защищен от записи" 9920 IF ERR-71 THEN Е|="Неготовность дисковода" 9922 IF ERR;72 THEN Е|="Плохое магнитное покрытие диска" 9924 IF ERR=73 THEN Е$="Требуется интерпретатор BASICA" 9926 IF ERR;24 OR ERR=25 OR ERR:57 THEN Еф="Неисправность или ошибка B/B" 9928 IF ERR=7 OR ERR=14 THEN E$="He хватает памяти" 9930 LOCATE 14,30 9940 COLOR 1,0:REM подчеркивание 9950 PRINT E| 9960 COLOR 7,0:REM нормальное отображение 9970 E$="" 9980 GOSUB 4010:REM пауза 9990 RESUME 10000 Рис. 3.12. Распечатка процедуры обработки ошибок (использующей весь экран) Сама процедура обработки ошибок состоит из строк 9800— 9990. Строки 9800 — 9850 привлекают внимание оператора, очи¬ щая экран и выдавая на динамик звуковой сигнал, а на экран по центру 6-й строки сообщение «ОШИБОЧНАЯ СИТУАЦИЯ». Строки 9870—9900 выводят на экран код ошибки и номер строки, содержащей ошибку. Затем в строках 9910—9928 определяется сообщение, соответствующее ошибке. В строке 9910 устанавли¬ вается стандартное (принимаемое по умолчанию) сообщение: «Ошибка в программе или в файле». Большинство ошибок, за которые оператор не ответствен, входят в эту категорию или по крайней мере близки к ней. В строках 9912—9928 производятся проверки типа 1F—THEN на коды самых распространенных ошибок оператора и в строковую переменную Е$ помещается со¬ общение об этой ошибке. Строки 9930—9950 выводят подчеркнутое сообщение об ошиб¬ ке. Строка 9970 сбрасывает Е$, присваивая этой переменной 92
пустое значение, строка 9980 вызывает подпрограмму паузы, а строка 9990 возобновляет работу программы со строки 10000. Заметим, что фрагмент программы, в котором определяется сообщение об ошибке (строки 9910—9928), может выполняться быстрее, если включить в конец каждой из строк оператор GOTO 9930. Но его отсутствие в конце строки экономит несколько байт памяти. Надо надеяться, что процедура обработки ошибок не бу¬ дет вызываться столь часто, чтобы скорость ее работы имела какое-нибудь значение. Вид экрана при возникновении ошибки изображен на рис. 3.13. Рис. 3.13. Кадр вывода, который формируется изображенной на рис. 3.12 процедурой обработки ошибок Однострочная процедура. В некоторых случаях вам не захо¬ чется разрушать весь кадр для выдачи сообщения об ошибке и вы предпочтете поместить его в одну строку. Только что описан¬ ную процедуру нетрудно модифицировать так, чтобы она делала именно это. Пересмотренная процедура изображена на рис. 3.14. Так как этот программный текст несложен и основан на уже рас¬ смотренном фрагменте, оставлю его разбор вам. Однако обрати¬ те внимание, что строка 9990 этой процедуры, в отличие от преды¬ дущей, указывает RESUME NEXT вместо RESUME 10000. Ва¬ риант RESUME NEXT был выбран в предположении, что про¬ граммист пожелает так организовать процедуру обработки оши¬ бок, чтобы она предупреждала и информировала оператора, но не нарушала работу программы, передавая управление другой ее 93
0 rem процедура обработки ошибок (одна строка) 1 REM SAVE"А:FIG3-14",А 9600 REM--Процедура обработки ошибок (одна строка)-- 9605 REM ВНИМАНИЕ: подпрограмма требует 80-столбцового дисплея 9806 REM если вы работаете с 40-столбцовым, переформатируйте в две строки 9810 ВЕЕР 9830 LOCATE 2 3, 1 9840 COLOR 0,7:REM инверсия 9850 PRINT "ОШИБКА” 9660 COLOR 7,0:REM нормальное отображение 9870 LOCATE 23,7 9880 PRINT" с кодом ’••.ERR;" в строке ";ERL;*: "; 9910 Еф:"Ошибка в программе или в файле" 9912 IF ERR:53 THEN Еф:"файл не найден" 9914 IF ERR:58 THEN Еф:"файл уже существует" 9916 IF ERR:61 THEN Еф-"На диске не осталось места" 9918 IF ERR;70 THEN Е|="Диск защищен от записи" 9920 IF ERR=71 THEN Еф="Неготовность дисковода" 9922 IF ERR:72 THEN Еф:"Плохое магнитное покрытие диска" 9924 IF ERR:73 THEN Еф:"Требуется интерпретатор BASICA" 9926 IF ERR:24 OR ERR:25 OR ERR:57 THEN Еф:"Неисправность или ошибка B/B" 9928 IF ERR:7 OR ERR:14 THEN Еф:"Не хватает памяти" 9940 COLOR 1,0:REM подчеркивание 9950 PRINT Еф 9960 COLOR 7,0:REM нормальное отображение 9970 Еф:"" 9990 RESUME NEXT Рис. 3.14. Распечатка процедуры обработки ошибок (использую¬ щей одну строку экрана) части. В случае ошибки процедура выводит сообщение в строку 23 экрана. Формат сообщения изображен на рис. 3.15. (Сообще¬ ние можно вывести и в другой строке экрана. Для этого достаточ¬ но изменить аргументы оператора LOCATE в строке 9870.) Рис. 3.15. Кадр вывода, формируемый изображенной на рис. 3.14 процедурой обработки ошибок 94
Испытать процедуру обработки ошибок можно с помощью оператора ERROR языка Бейсик, сопровождаемого кодом ошиб¬ ки. BASIC интерпретирует этот оператор как указание на то, что в строке, содержащей оператор ERROR, допущена соответст¬ вующая ошибка. Если, например, Бейсик встретит в программе такой оператор: 20 ERROR 58, ’ то он будет действовать точно так же, как если бы при выполне¬ нии строки 20 произошла ошибка номер 58. Если до оператора ERROR не был выполнен ни один оператор ON ERROR GOTO, то программа прекратит работу. Если такой оператор выполнял¬ ся, то управление будет передано на процедуру обработки оши¬ бок. С помощью оператора ERROR вы можете проверить процеду¬ ры обработки ошибок, приведенные на рис. 3.12 и 3.14, или ваши собственные процедуры. Вставьте, например, в свою программу следующие строки: 10 ON ERROR GOTO 9800 20 ERROR 58 30 PRINT «Строка 30» 10000 PRINT «Строка 10000» Затем выполните программу. В зависимости от того, какой из вариантов оператора RESUME содержится в строке 9990: 9990 RESUME 9990 RESUME NEXT ИЛИ ‘ 9990 RESUME 10000 программа будет выполнять разные действия. Испытайте ее с операторами RESUME всех трех разновидностей и посмотрите, что при этом будет происходить. Хотя такие процедуры обработки ошибок и полезны^ они, конечно, не заменят систематического тестирования программы с целью предотвращения ошибок, за которые ответствен програм¬ мист. Уменьшить число ошибок оператора можно также с помощью выводимых на экран подсказок и предоставления хорошей доку¬ ментации. Эти вопросы будут обсуждаться в последующих гла¬ вах.
Глава 4 ПРОЕКТИРОВАНИЕ ВЫДАЧИ И ФОРМАТА КАДРОВ В данной главе сообщаются основные сведения о проектиро¬ вании выдачи и формата кадров вывода. Экран — монитор или телевизор — это окно компьютера в мир. Через это окно компью¬ тер выдает пользователям разного рода информацию: фразы на русском (или других) языке, числа, графики, предупреждения, запросы, указания и вообще все, что может придумать програм¬ мист. Задача программиста — спроектировать такой формат вы¬ дачи, который позволит пользователю легко воспринимать инфор¬ мацию и на который в то же время приятно смотреть. Способ¬ ность проектировать формат выдачи, удовлетворяющий обоим требованиям, в известной мере является искусством и определя¬ ется художественными способностями программиста. С другой стороны, проектирование формата выдачи является и предметом технической науки, причем существует ряд прове¬ ренных опытом правил, которые должны помочь вам в работе. Одно из правил заключается в следующем: при выводе сообще¬ ний располагайте их по центру экрана. Это очень просто делать, но на удивление много программистов либо не думают о красоте кадра, либо просто не утруждают себя такой работой. Основное назначение каждого кадра вывода — передача ин¬ формации пользователю. На качество передачи влияют многие факторы, в том числе: • объем представляемой информации; $ способ ее представления: с помощью слов, чисел или гра¬ фиков; Ф скорость поступления информации; • используемые цвета; е формат кадра. Качество передачи информации определяется также и други¬ ми, менее объективными факторами, например тем, насколько приятно для глаза изображение на экране. Возможно ли спроек¬ тировать уродливый кадр — настолько плохой, что он оттолкнет пользователей от программы? Конечно, возможно, и многие не¬ задачливые программисты это продемонстрировали. Поэтому, 96
приводя некоторые технические сведения о проектировании формата кадров, немного поговорим и об эстетике. Большинство обсуждаемых в главе рекомендаций проектиро¬ вания выдачи иллюстрируется примерами текстов на языке Бей¬ сик. Разбирая примеры, выполните их на своем ПК. Тогда вы и научитесь большему, и учеба будет интереснее. В этой главе рас¬ сматриваются следующие вопросы: • принципы проектирования; • использование цвета; • использование специальных режимов отображения; • управление курсором; • очистка строки или ряда строк; • доступ к экрану; • расположение данных на экране; • отображение текста; • отображение чисел; • проектирование печатных отчетов. ПРИНЦИПЫ ПРОЕКТИРОВАНИЯ Наиболее важные принципы проектирования кадров вывода — простота и последовательность. Это универсальные принципы, имеющие отношение не только к проектированию форматов кад¬ ра. Они распространяются и на многие другие задачи проектиро¬ вания программ: прием данных от пользователя, управление программой и др. Как применить эти общие принципы к проектированию кадров вывода? Рассмотрим первый принцип. Пусть кадры будут просты¬ ми, не перегруженными подробностями и сконцентрированными на одной мысли. Вы не завоюете никаких наград, если попытае¬ тесь впихнуть в один кадр как можно больше информации. Вы просто запутаете тех, кто будет работать с вашей программой. Проектируйте кадры так, чтобы на экране оставалось свобод¬ ное место. Выдавайте информацию небольшими порциями. Принцип последовательности требует, чтобы в разных кадрах информация была представлена одинаковым образом. Тогда поль¬ зователю будет проще учиться и запоминать формат выдаваемых ему данных. Если, например, в некоторых кадрах подсказки вы¬ водились в нижней части экрана, то, естественно, пользователь будет ожидать, что и в других кадрах они появятся в том же месте. Не обманывайте ожидания пользователя — тогда ему бу¬ дет легче работать. Те же соображения применимы и к другим элементам кадров, например к их заголовкам, меню, предупреж¬ дениям и самому информационному содержанию. 4 Зак. 1488 97
ИСПОЛЬЗОВАНИЕ ЦВЕТА Многие читатели имеют ПК с цветными дисплеями, поэтому необходимо обсудить, как пользоваться цветом. Но так как мы предполагаем, что большинство читателей обладают монохромны¬ ми дисплеями, цвет обсудим кратко. Основная цель данного раз¬ дела — ознакомить читателей, владеющих цветными дисплеями, с некоторыми простыми правилами использования цвета. Цвет специально рассматривается только в настоящем параграфе. Все примеры программных текстов, приведенные в других частях книги, рассчитаны на монохромный дисплей. Если ваш дисплей монохромный, этот раздел можно пропустить. Хотя при серьезном программировании цвет используется все чаще, в сущности, большая часть серьезных программ в нем не нуждается. Читатели, имеющие монохромные дисплеи, не должны чувствовать себя обделенными. Нельзя, однако, полностью игно¬ рировать эту тему, так как с цветом часто неправильно обраща¬ ются. Цвет следует применять не для внешнего эффекта, а для какой-нибудь полезной цели. При выборе цветовых сочетаний про¬ граммисту опасно полагаться лишь на интуицию и вкус. Неквали¬ фицированное владение цветом часто не облегчает, а затрудняет чтение кадра и к тому же может вызвать боль в глазах. Пользоваться цветом сложно. Кроме знания характеристик оборудования и программного обеспечения, необходимо иметь еще и некоторые представления о том, как цвет воспринимается человеком. В данном параграфе даются некоторые практические рекомендации по использованию цвета и обсуждается, как избе¬ жать ряда распространенных ошибок. Сосредоточим внимание на применении цвета для передачи информации, а не для созда¬ ния внешнего эффекта. Для представления информации на любом дисплее требуется как минимум два цвета. Можно воспользоваться любой парой цветов, воспроизводимой оборудованием и различаемой пользо¬ вателем. Один цвет нужен как фон или цвет поля, на котором представляют информацию в другом, контрастирующем цвете; При этом основная забота программиста заключается в подборе сочетания цветов фона и знаков. Цвет можно использовать и по-другому, например возможен вывод в одном кадре знаков различного цвета, а также примене¬ ние цветового кодирования, т. е. представление данных, принад¬ лежащих разным классам, различными цветами. Однако обсуж¬ дение цветового кодирования выходит за рамки данной книги. Кроме того, цвет может придать программе блеск, но серьезным программам, как правило, это, в общем-то, ни к чему. Во всяком случае решать, как применять цвет в эстетических целях, должен скорее художник, а не программист. 98
Данный параграф начинается с изложения способа управле¬ ния цветом на ПК. Далее рассматриваются контрастность цветов, выбор контрастирующих пар и рекомендуются некоторые соче¬ тания цвета символов и фона. УПРАВЛЕНИЕ ЦВЕТОМ Бейсик ПК фирмы IBM позволяет выбирать цвета символов, фона и рамки кадра. Цвета устанавливаются с помощью опера¬ тора COLOR, имеющего следующий формат: COLOR, символы, фон, рамка Этот оператор действует по-разному в зависимости от того, подключен ли к компьютеру цветной монитор (с помощью адап¬ тера цветной графики) или монохромный монитор (с помощью адаптера монохромного монитора и принтера). В данном парагра¬ фе предполагается, что к ПК подключен цветной монитор, а в следующем параграфе обсуждается, как оператор COLOR будет действовать с адаптером монохромного монитора и принтера. ПК фирмы IBM может представлять на экране 16 различных цветов. В текстовом режиме1 допустимы 16 цветов символов, 8 цветов фона и 16 цветов рамки в любых сочетаниях. В графи¬ ческом режиме число допустимых сочетаний более ограничено. Последующее изложение относится только к текстовому режиму отображения. ЦВЕТ код Черный 0 Синий (темный) 1 Зеленый (темный) 2 Голубой (темный) 3 Красный (темный) 4 Фиолетовый (темный) 5 Коричневый 6 Белый 7 Серый 8 Синий (яркий) 9 Зеленый (яркий) 10 Голубой (яркий) 11 Красный (яркий) 12 Фиолетовый (яркий) 13 Желтый 14 Белый (яркий) 15 Т а 6 л. 4.1. Коды цветов, отображаемых на экра¬ не ПК фирмы IBM 1 Режим отображения задается оператором SCREEN языка Бейсик. Если вы не знакомы с этим понятием, обратитесь к соответствующему руководству.— При- меч. пер. 4* 99
Цвета, которые можно вывести на дисплей ПК фирмы IBM, приведены в табл. 4.1. Цвет устанавливается с помощью опера¬ тора COLOR. Коды цветов, используемые в качестве аргументов этого оператора, определяются по табл. 4.1. Например, чтобы сделать цвет символов белым, фона — черным, а рамки — корич¬ невым, воспользуйтесь таким оператором: COLOR 15,0,6 Если к параметру цвета символов прибавить число 16, то символы будут мигать. Например, оператор COLOR17,0,.0 создает синие знаки, вспыхивающие на черном фоне и в черной рамке. Символы можно выводить любым из 16 цветов, приведенных в таблице, а, вставив в программу несколько операторов COLOR с разными аргументами, можно использовать разные цвета в од¬ ном кадре вывода. Цвет рамки можно выбрать любым из 16. Од¬ нако цвет фона должен быть одним из восьми, перечисленных в таблице первыми (коды от 0 до 7), а поскольку в том, чтобы фон и рамка были разных цветов, нет никакого смысла, фактически число цветов фона сводится к восьми. Эти цвета являются тем¬ ными вариантами остальных восьми цветов. Например, цвет 1 — темно-синий, а цвет 9 — светло-синий. Большинство цветов фо¬ на — темные, а это значит, что в большинстве допустимых соче¬ таний светлые символы отображаются на темном фоне. Кроме того, поскольку серый цвет (номер 8) нельзя употреблять как фоновый, в качестве фона или рамки можно использовать только два нейтральных цвета — белый и черный, они, как правило, соз¬ дают высококонтрастное изображение с любым цветом символов. На рис. 4.1 приведена подпрограмма задания цвета. Ее аргу¬ ментами являются переменные: CHAR: код цвета символов (0—15), BACK: код цвета фона (0—8), BORD: код цвета рамки (0—15). Перед тем как воспользоваться данной подпрограммой, задайте значения переменных CHAR, BACK и BORD (это лучше всего делать в начале программы), а затем с помощью оператора GOSUB 1200 установите начальные цвета. С помощью той же подпрограммы можно менять цвета. На¬ пример, вы можете пользоваться различными сочетаниями цветов 0 REM Подпрограмма установки цвета экрана 1 REM SAVE”A:FIG4-1 ”, А 1020 REM--Установить цвета дисплея-- 1030 COLOR CHAR, BACK. BORD 1040 RETURN Рис. 4.1. Подпрограмма установки цвета ото¬ бражения на экране 100
в разных частях программы, чтобы помочь пользователю лучше в ней ориентироваться. Определенные сочетания цветов можно использовать для предупреждений, а также для привлечения внимания пользователя к ошибкам или ситуациям, требующим его действий. С помощью рассматриваемой подпрограммы можно изменить любую компоненту сочетания цветов. После начальной установки цветов символов, рамки и фона последующие вызовы подпро¬ граммы требуют задания только одного аргумента, скажем цвета символов. Это делает данную подпрограмму несколько более удоб¬ ной, чем прямое использование оператора COLOR. Но так как данная подпрограмма предельно проста (она состоит из одного оператора COLOR с соответствующими аргументами), некото¬ рые программисты, наверное, предпочтут использовать оператор COLOR. Если вы не собираетесь использовать рамку, отличающуюся по цвету от фона, то соответствующие аргументы следует сделать идентичными. Иначе говоря, измените строку 1030 подпрограммы на следующую: 1030 COLOR CHAR, BACK, BACK Применяя в серьезных программах цвет, будьте сдержаны. В серьезных программах он оправдан только тогда, когда служит полезной цели, например, помогает поиску информации на экране или является информационным кодом. В некоторых кадрах он может быть использован в обеих целях. Кроме того, он полезен для выделения различных областей экрана: разные зоны можно окрасить в разные цвета. Этот способ разбиения кадра на несколь¬ ко блоков эффективен, не пользоваться им следует с осторожно¬ стью, чтобы избежать взаимодействия цветов по границе зон и слишком сильных контрастов.Те же проблемы могут возникнуть при выборе сочетаний цветов символов и фона, описываемом в следующем параграфе. КОНТРАСТ Для представления пользователям информации, поступающей из ПК на экран, выдаются символы. При этом надо установить их цвет и цвет фона. Например, экран может содержать белые символы на черном фоне. Этот контраст можно инвертировать, представив черные символы на светлом фоне. Что лучше: отображать светлые символы на темном фоне или наоборот? Ответ зависит в основном от освещенности того места, где стоит дисплей. В светлом помещении предпочтительнее тем¬ ные символы на светлом фоне. В затененном помещении целе¬ сообразней выводить светлые символы на темном фоне. Дело в том, что глаз приспосабливается к уровню окружающего освеще- 101
нияу и если яркость экрана близка к общей освещенности, то изображение восприниматься будет лучше. Сильный контраст между символами и фоном, вообще гово¬ ря, облегчает чтение. Высококонтрастное изображение, например белые символы на черном фоне, воспринимается легче, чем низко¬ контрастное, например голубые символы на синем фоне. Но силь¬ ный контраст может утомить глаза. Темными символами на светлом фоне в последнее время поль¬ зуются все чаще, но большинство программистов по-прежнему используют светлые символы, выводя их на темном фоне. Как отмечалось выше, нельзя сказать заранее, какой способ лучше: это определяется конкретной ситуацией. Кроме того, большин¬ ство пользователей имеет те или иные личные склонности, кото¬ рые тоже следует учитывать. ВЫБОР ЦВЕТА ПК фирмы IBM может представлять знаки в 16 цветах, а фон — в 8, так что существует 120 сочетаний, в которых цвет фона не совпадает с цветом символов. Казалось бы, нам доступно мно¬ жество вариантов. В каком-то смысле так оно и есть, но когда мы начинаем исключать недопустимые сочетания, то убеждаемся в том, что число возможных сочетаний быстро уменьшается. Рассмотрим сначала цвет фона. Я бы порекомендовал только два из них: белый и черный. Цветовой фон не дает ничего, кроме красоты. Фон нужен только для контраста с символами. Кроме того, некоторые цвета фона, например красный, фиолетовый, желтый, синий и оранжевый, вступают в конфликт с цветами, которые можно использовать для представления информации. Если например, вы используете совместно красный и синий цвет, то создается иллюзия тени- вдоль границы их соприкосновения. То же самое можно сказать о сочетании желтого и зеленого цвета. Итак, мы ограничиваемся двумя цветами фона: черным и белым. Им соответствуют два уровня яркости: черному — темный, бело¬ му — светлый. Рассмотрим теперь цвета символов. Прежде всего отметим, что некоторые цвета могут использоваться как для фона, так и для символов. Это относится, в частности, к черному и белому цветам. Некоторые цвета, в частности синий, голубой, красный, фиоле¬ товый и коричневый, редко используются для представления ин¬ формации. В этих цветах нет ничего дурного, но к большинству из них глаз слабо чувствителен. Остаются желтый и зеленый цвета. Есть два оттенка зеленого: темный и светлый. Есть только один оттенок желтого. Как ни странно, три оставшихся сочетания цветов близки к цвету фосфо¬ ра трех наиболее популярных видов монохромных мониторов: белого, зеленого и янтарного. 102
РЕКОМЕНДУЕМЫЕ ЦВЕТА Рекомендуемые сочетания цветов символов и фона приведены в табл. 4.2. В ней указаны два цвета фона: черный и белый. ЦВЕТ ФОНА Черный Белый ЦВЕТА СИМВОЛОВ Белый, желтый, зеленый (яркий) Черный, серый Табл. 4.2. Рекомендуемые сочетания цветов фона и символов Перед тем как окончательно выбрать цвета кадра, опробуйте несколько комбинаций цвета. На рис. 4.2 приведена короткая программа, которая генерирует на экране различные цвета фона и символов и позволяет посмотреть, как они выглядят. Введите эту программу в свой компьютер и запустите ее. В начале работы программы вы получите запрос на ввод цвета фона (число от О до 7, см. табл. 4.1). Затем запрашивается цвет символов. Введите некоторое значение из табл. 4.1. Когда вы нажмете клавишу «Ввод», экран примет указанный цвет и начнет заполняться сим¬ волами заданного цвета. Затем появится новый запрос цвета сим¬ волов, позволяющий породить новое изображение символов на старом фоне. Если вы пожелаете выбрать другой цвет фона, то прервите работу программы- с помощью клавиш Ctrl—Break и запустите ее заново. 0 REM Программа установки цветов 1 REM SAVE"А:FIG4-2" , А 10 INPUT -фон: **; BACK 20 INPUT иСимволы: ";CHAR 30 COL*OR CHAR, BACK, BACK 40 CLS 50 FOR X=1 TO 40 60 PRINT"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; 70 NEXT 80 PRINT 90 PRINT 100 GOTO 20 Рис. 4.2. Программа генерации сочетаний цвета фона и символов Может показаться, что при столь богатых возможностях стыдно ограничиваться лишь несколькими рекомендованными цветами. Почему бы не попробовать выдать красные символы на синем фоне или фиолетовые на черном? Хотя на такие сочетания цветов бывает приятно смотреть, пользователю будет трудно с ними работать, так что при выборе цветов кадра следует быть 103
крайне осмотрительным. Не спорю: рекомендуемые сочетания кон¬ сервативны, и допустимы эксперименты с другими сочетаниями. Но если у вас есть хоть тень сомнения, то лучше придерживайтесь сочетаний цветов, указанных в табл. 4.2. Если вы располагаете монохромным монитором, подключен¬ ным к адаптеру цветной графики, то цвета будут преобразованы в оттенки серого. Но и тогда вам придется решать, выводить ли светлые символы на темном фоне или, наоборот, устанавливать «цвета» так, чтобы обеспечить достаточную контрастность. ОСОБЫЕ РЕЖИМЫ ОТОБРАЖЕНИЯ ПК может выводить символы либо в «нормальном» режиме, то есть светлые символы на темном фоне, либо в следующих осо¬ бых режимах: • режим инверсии: темные символы на светлом фоне; • режим подчеркивания; • режим мигания (нормальный): светлые символы вспыхи¬ вают на темном фоне; • режим мигания (инверсный): темные символы вспыхивают на светлом фоне; • режим повышенной яркости. Приведенные особые режимы задаются с помощью оператора COLOR и требуют, чтобы в ПК был установлен адаптер моно¬ хромного монитора и принтера. (Режим мигания совместим и с адаптером цветной графики. Для этого в первом аргументе опе¬ ратора COLOR к коду цвета символов следует прибавить число 16.) Адаптер монохромного монитора и принтера воспринимает оператор COLOR иначе, чем адаптер цветной графики. Послед¬ ний меняет цвет, а первый интерпретирует аргументы оператора COLOR как коды режима отображения. При этом учитываются только два первых аргумента. Иначе говоря, оператор COLOR имеет следующий формат: COLOR аргумент 1, аргумент 2 Аргумент 1 задает цвет символов и режим отображения. Ар¬ гумент 2 устанавливает цвет фона. Перечислим значения аргу¬ мента 1 и укажем их смысл: О — черный символ, 1 — подчеркнутый символ, 2—7 — светлый символ. Добавив к этому аргументу число 8, получим символ повы¬ шенной яркости, а добавив число 16, заставим символ мигать. Аргумент 2 определяет цвет фона: выбор чисел 0—6 делает его темным, а числа 7 — светлым. Эти указания могут привести вас в замешательство. И не удивительно, ведь различных значений аргументов оператора 104
COLOR гораздо больше, чем режимов отображения. Сопостав¬ лять диапазоны значений аргументов режимам отображения чрез¬ вычайно трудно. Задача станет проще, если учесть, что существу¬ ет всего пять основных режимов отображения: остальные явля¬ ются их сочетаниями. Вообще говоря, всегда лучше пользоваться во всей программе одним, заранее выбранным способом установки режима отображения. Приведем принятые в данной книге согла¬ шения: нормальное отображение режим инверсии режим подчеркивания режим мигания режим мигания (инверсный) режим повышенной яркости режим подчеркивания и повышен¬ ной яркости режим подчеркивания и мигания режим подчеркивания, мигания и повышенной яркости режим мигания и повышенной яркости COLOR 7,0 COLOR 0,7 COLOR 1,0 COLOR 23,0 COLOR 16,7 COLOR 15,0 COLOR 9,0 COLOR 17,0 COLOR 25,0 COLOR 31,0 В каких случаях целесообразно обращаться к специальным режимам отображения? Этот вопрос решается в соответствии с приведенными ниже рекомендациями, хотя программист может несколько отклоняться от них, руководствуясь своим личным стилем и склонностями. Прежде всего отметим, что в большинстве случаев следует пользоваться режимом нормального отображения. Он создает тот фон, с которым контрастируют специальные режимы. Отличаясь от режима нормального отображения, они будут (или по крайней мере должны) привлекать внимание и выделять выдаваемую ин¬ формацию. Внимание лучше всего привлекается миганием. Инвер¬ сия, подчеркивание и повышенная яркость также привлекают внимание, но не так эффективно, как мигание. Поэтому режим ми¬ гания традиционно используется для сообщений об ошибках и прочих сообщений, требующих немедленной реакции пользовате¬ ля. Три остальных режима — инверсия, подчеркивание и повышен¬ ная яркость — обычно применяются для выделения информации. В печатном тексте подчеркивание и повышенная яркость соответст¬ вуют курсиву, инверсия не имеет общепринятого аналога. Режим инверсии часто используют для заголовков, что позволяет отли¬ чать их от информационного содержания кадра. Короче говоря, можно дать следующие рекомендации: • мигание используйте для предупреждений; • инверсию употребляйте для заголовков и «шапок»; • подчеркивание и повышенную яркость применяйте для выде¬ ления. 105
Обратите внимание на то, что особые режимы отображения можно употреблять совместно. Возможны не только инверсия, подчеркивание и мигание, но и любое их сочетание. Не забывайте, однако, что режим отображения является информационным кодом, т. е. сам несет некоторую информацию. Пользователю трудно дер¬ жать в уме более 5—7 различных кодов. Поэтому лучше не увле¬ каться предоставленными вам возможностями. Ведь вам не хо¬ чется, чтобы в конце долгого трудового дня пользователь ломал себе голову, стараясь вспомнить разницу между обычным мига¬ нием, мигающим сообщением, которое еще и подчеркнуто, мигаю¬ щим сообщением повышенной яркости и... в общем, ясно. Пожа¬ луйста, попроще! В режиме инверсии можно получить отрицательное отображе¬ ние, т. е. кадр со светлым фоном и темными символами на нем. Отрицательное отображение обсуждалось в предыдущем параграфе. Но мне кажется, что на мониторах с зеленым фосфо¬ ром и аналогичных дисплеях отрицательными кадрами лучше не пользоваться. Эти мониторы лучше смотрятся в режиме нормаль¬ ного отображения. Применяйте инверсию скудно и только для вы¬ деления. УПРАВЛЕНИЕ КУРСОРОМ Необходимо уметь управлять положением курсора. Вы должны иметь возможность быстро и легко перемещать его в нужное место экрана. Это обеспечит вам свободу при формировании кадров вы¬ вода. Кадры можно формировать, не особенно задумываясь над тем, где расположен курсор. Например, можно очистить экран, вывести первую строку, за ней вторую и так далее, пока последняя строка не дойдет до нижнего края экрана (рис. 4.3). Но такой спо¬ соб формирования кадров не всегда бывает удобен. Он хорош для простейших кадров, но плох для сложных. Нередко бывает удобнее формировать кадр по частям, напри¬ мер вначале вывести заголовки, а затем выдать остальную инфор¬ мацию (рис. 4.4). Но для этого необходимо иметь возможность в нужный момент переместить курсор в другую позицию. Это осво¬ бодит вас от необходимости построчного формирования кадра. К счастью для программистов, работающих на ПК, в версии языка Бейсик для этого типа компьютеров есть оператор LOCATE, который позволяет переместить курсор в любую точку экрана.. Позиция курсора задается ее координатами по горизонтали и вер¬ тикали, как показано на рис. 4.5. Номер строки должен находиться в диапазоне от 1 до 25, а номер столбца — от 1 до 80 (или, если используется 40-столбцовый дисплей, от 1 до 40). 106
Рис. 4.3. Если очистить экран и принимать вводимые показатели, не управляя расположением подсказок, то каждая подсказка будет Рис. 4.4. Имея возможность управлять положением курсора, можно выводить данные в различные части экрана в том порядке, который представляется удобным. Числа в кружках указывают порядок выво¬ да элементов данных на экран 107
Рис. 4.5. Координаты изображения на экране, состоящего из 80 столбцов. Номера строк (1—25) отсчитываются сверху вниз 108
Оператор LOCATE имеет следующий синтаксис: LOCATE V, Н где аргумент V задает номер строки (1—25), а аргумент Н — номер столбца (1—80). Для того чтобы, Например, поместить курсор в столбец 56 строки 10, применяется такой оператор: LOCATE 10, 56 В операторе LOCATE можно задавать не только два, но и один аргумент. Если один из аргументов опускается, то оператор работает с его текущим значением. Так, после выполнения двух следующих операторов курсор окажется в строке 20, столбце 40: 10 LOCATE 20,10 20 LOCATE,40 Аналогично после выполнения двух следующих строк курсор передвинется в строку 12, столбец 36: 10 LOCATE 1,36 20 LOCATE 12 Оператор LOCATE обладает и другими возможностями. С его помощью можно управлять размером курсора и делать его невидимым. Подробности можно найти в руководстве по языку BASIC. Для иллюстрации того, как при формировании кадра вывода можно использовать оператор LOCATE, предположим, что вы разметили кадр, изображенный на рис. 4.6, и хотите составить небольшую программу, которая будет порождать этот кадр, выводя вначале заголовки, а затем помещая в соответствующие поля данные. Такая программа изображена на рис. 4.7. Вывод заголовков начинается в строке 11000, а вывод данных — в строке 12000. Представьте, что пришлось бы делать для построчного форми¬ рования подобного кадра. Выводить сначала заголовки, а затем данные намного проще. Одно из достоинств оператора LOCATE состоит в том, что с его помощью легко управлять курсором при горизонтальном табулировании. Параметр TAB оператора PRINT позволяет выво¬ дить данные в определенной позиции по горизонтали, но он не всегда подчиняется приказам программиста. Для проверки этого утверждения наберите и выполните такую программу: 10 PRINT TAB (10) ”АААА”; 20 PRINT TAB (12) ”ВВВВ” В результате две строки символов будут выведены в различ¬ ных строках экрана: АААА вввв 109
0 REH Программа формирования кадра дисплея 1 REM SAVE"А:FIG4-7" , А 10000 REM формирование кадра 10010 КЕМ--Вывод заголовков-- 10020 CLS 10025 COLOR 0,7:REM инверсия 10030 LOCATE 1, Зв 10040 PRINT"ЗАГОЛОВОК” 11000 REM--Вывод "шапок"-- 11010 LOCATE 3, 20 11020 PRINT” ШАПКА 1 ” 11030 LOCATE 3,50 11040 PRINT” ШАПКА 2: " 11050 LOCATE 12,20 11060 PRINT” ШАПКА 3 ” 11070 LOCATE 6,50 11060 PRINT” ШАПКА 4: ” 11090 COLOR 7,0:REH нормальное отображение 12000 REH--ВЫВОД ДАННЫХ-- 12010 REM-Данные 1- 12020 FOR Vz4 TO 7 12030 LOCATE V, 21 12040 PRINT”данные 1” 12050 NEXT 12060 REM-Данные 2- 12070 LOCATE 3,62 12060 PRINT”flaHHbie 2” 12090 REM-Данные 3- 12100 FOR Vrl3 TO 16 12110 LOCATE V,21 12120 PRINT"данные 3" 12130 NEXT 12140 REM-Данные 4- 12150 LOCATE 6,62 12160 PRINT"данные 4” 12170 LOCATE 23, 1 12180 END Рис. 4.7. Программный текст, формирующий изображенный на рис. 4.6 кадр. Вначале выводят¬ ся заголовки, а затем значения данных Ваша программа приказала компьютеру вывести строку АААА в позиции 10, а строку ВВВВ в позиции 12. Вторая строка должна была перекрыть первую. Что же произошло? BASIC сохранил обе строки символов, выведя их в разных строках экрана, вместо того, чтобы напечатать их одна поверх другой. Он помог вам, хотя вы его об этом и не просили. Мне не хотелось бы заходить слишком далеко, сравнивая машину с человеком, но могу себе представить, как BASIC говорит примерно следующее: «Этот бедный простофиля, конечно, не хо¬ тел, чтобы одна строка перекрывала другую! Я исправлю его ошиб¬ ку, передвинув второй элемент данных в следующую строку экра¬ на». 110
Теперь предположим, что вы умеете работать с параметром TAB и как раз хотите, чтобы строки перекрывали друг друга. Тогда ваше дело плохо. С помощью параметра TAB вы сделать это не сможете. TAB рассматриваемой версии языка Бейсик в этом отношении не уникален. В большинстве машин этот параметр работает точно так же. Кроме того, TAB не позволяет выводить данные справа нале¬ во, т. е. в обратном направлении. Измените приведенную выше программу следующим образом: 10 PRINT TAB (30) ”АААА”; 20 PRINT TAB (10)”ВВВВ” и запустите ее. Строки АААА и ВВВВ появятся в разных стро¬ ках экрана. BASIC не позволяет перемещать курсор в обратном направлении с помощью параметра TAB. С оператором LOCATE вы таких трудностей испытывать не будете. Попробуйте набрать и запустить такую программу: 10 LOCATE 10,10 20 PRINT ’’АААА”; 30 LOCATE 10,12 40 PRINT ”ВВВВ” На экране, начиная со столбца 10, появится строка ААВВВВ. Та¬ ким образом, оператор LOCATE позволяет, если вы пожелаете, перекрывать одно сообщение другим. Кроме того, с его помощью можно осуществить вывод сообще¬ ний в обратном порядке. Измените строки 10 и 30 следующим обра¬ зом: 10 LOCATE 10,30 30 LOCATE 10,10 и запустите программу. Строка АААА появится в столбце 30, а строка ВВВВ — в столбце 10: сообщения выведены в обратном по¬ рядке. СТИРАНИЕ СТРОКИ ИЛИ РЯДА СТРОК При формировании кадров вывода часто бывает нужно стереть содержимое части экрана. Весь экран можно очистить с помощью оператора CLS, но не существует простого способа очистки части экрана. Стирать и формировать заново весь кадр, когда нужно из¬ менить лишь небольшую его часть, очень неудобно. Мало того, что это лишняя работа: она еще и раздражает пользователя, перед которым периодически то гаснет, то вновь появляется изо¬ бражение. Гораздо лучше очищать только нужную часть кадра. В общем случае бывают полезны три операции по очистке экрана: очистка одной строки, очистка с некоторой строки до конца экрана и очистка ряда строк. 111
Потребность в уничтожении отдельной строки может возник¬ нуть, например, перед выводом новой информации, выдачей под¬ сказки или приемом данных от пользователя. По аналогичным причинам может понадобиться очистить экран от текущего положения курсора и до конца экрана. Нижнюю часть кадра часто бывает удобно стереть, чтобы освободить место для вывода данных или, скажем, меню. Возможность стереть ряд строк чаще всего бывает полезной при удалении текстов и таблиц, расположенных в средней части кадра. Хотя такую очистку можно выполнять и с помощью операторов, включенных в основную часть программы, но,так как она выполня¬ ется достаточно часто, для нее целесообразно составить специаль¬ ные подпрограммы. Написать их на языке Бейсик достаточно просто. СТИРАНИЕ ОТДЕЛЬНОЙ СТРОКИ На рис. 4.8 приведен листинг подпрограммы, с помощью кото¬ рой можно очистить отдельную строку. Эта подпрограмма имеет следующие аргументы: WIDE % (число столбцов дисплея: 80 или 40), V (номер строки) и Н (номер столбца). Подпрограмма стирает все, что находилось в строке V справа от столбца Н, а за¬ тем возвращает курсор в позицию с координатами V, Н. Вызов подпрограммы очищает строку, а затем располагает курсор так, что на только что очищенное место можно сразу выводить дан¬ ные. REM Подпрограмма стирания одной строки 1 REM SAVE"A:FIG4-6" , А 1300 REM--Очистить одну СТРОКУ-- 1310 LOCATE V,H:REM переместить курсор в требуемую позицию 1320 PRINT SPACER (WIDE/.4-1-Н) REM стереть все до конца строки 1330 LOCATE V,H:REM вернуть курсор в требуемую позицию 1340 RETURN Рис. 4.8. Подпрограмма, стирающая данные до конца строки Внутреннее устройство подпрограммы просто. Строка 1310 вы¬ полняет первоначальную установку курсора. Строка 1320 с по¬ мощью функции SPACE$ выводит WIDE% + 1 —Н пробелов, стирая расположенные на экране данные с позиции курсора и до правой границы экрана. Затем строка 1330 возвращает курсор в позицию V, Н. Поскольку в пределах программы ширина экрана обычно не изменяется, переменную WIDE % следует установить равной 80 или.40 в самом начале программы, чтобы не делать этого при каждом вызове подпрограммы. Для использования этой подпрограммы следует задать ее ар¬ гументы, а затем вызвать ее с помощью оператора GOSUB. 112
Чтобы, например, стереть строку 15, начиная со столбца 24, сле¬ дует воспользоваться таким фрагментом программного текста: 11000 V=15 НОЮ Н = 24 11020 GOSUB 1300 Испытание программы, изображенной на рис. 4.9, дает вам возможность почувствовать, как эта подпрограмма работает. Эта коротенькая программа заполнит экран символами и позволит установить аргументы подпрограммы, а потом посмотреть, что про¬ изойдет при ее вызове. Введите эту программу в ПК и включите в нее подпрограмму, изображенную на рис. 4.8. 0 REM Демонстрационная программа 1 REM SAVE”A:FIG4-9. BAS”, А 10 REM--Демонстрационная программа-- 15 WIDEZ=60 20 CLS 30 INPUT ”V ”;V 40 INPUT ”H " ;H 50 CLS 60 FOR A=1 TO 44 70 PRINT "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567090!®#$”; 60 NEXT 90 PRINT 100 GOSUB 1300 110 COLOR 0,7 120 INPUT”ЭТО ПОДСКАЗКА!”, X$ 130 COLOR 7, 0 140 END Рис. 4.9. Программа, с помощью которой демонстрируется работа подпрограмм, изображенных на рис. 4.8, 4.10 и 4.11 ОЧИСТКА ДО КОНЦА ЭКРАНА Воспользовавшись подпрограммой, приведенной на рис. 4.10, вы можете стереть все, что расположено между позицией курсора и концом экрана. Эта подпрограмма имеет те же аргументы, что и предыдущая. 0 REM Подпрограмма стирания до конца экрана 1 REM SAVE”А_! FIG4-1 0" , А 1350 КЕМ--Стирание до конца экрана-- 1360 LOCATE V, H:REM переместить курсор в требуемую позицию 1370 PRINT SPACES(WIDE/+1-Н);:REM стереть все до конца строки 1380 FOR А:1 ТО 23-V:REM стереть все нижележащие строки 1390 PRINT SPACES(WIDEZ); 1400 NEXT 1410 LOCATE v,H:REM вернуть курсор в требуемую позицию 1420 RETURN Рис. 4.10. Подпрограмма, стирающая данные, начиная с текущей пози¬ ции курсора и до конца экрана 113
Рассматриваемая подпрограмма чрезвычайно проста. Строка 1370 очищает верхнюю строку экрана. Строки 1380—1400 сти¬ рают нижележащие строки. Обратите внимание, что данная под¬ программа очищает экран по 24-ю строку включительно. Если вы хотите стереть и строку 25, то замените в программной строке 1380 число 23 на 24. Испытайте эту подпрограмму, объединив ее с подпрограммой, изображенной на рис. 4.9, и из¬ менив в строке 100 вызов на GOSUB 1350. ОЧИСТКА РЯДА СТРОК Стереть ряд строк можно с помощью подпрограммы, изо¬ браженной на рис. 4.11. Аргументами данной подпрограммы явля¬ ются переменные WIDE % (число столбцов), VI (верхняя стро¬ ка) и V2 (нижняя строка). 0 REM Подпрограмма стирания ряда строк 1 REM SAVE”A:FIG4-11", А 1430 REM--Стереть ряд строк-- 1440 LOCATE VI, 1 1450 FOR А=1 ТО V2-V1+1 1460 PRINT SPACER (WIDE’/.) ; 1470 NEXT 1460 LOCATE VI, 1 1490 RETURN Рис. 4.11. Подпрограмма, стирающая ряд строк При вызове этой подпрограммы будут очищены все строки от VI до V2 включительно. Чтобы стереть, к примеру, строки 15—17, выполните следующие команды: 11000 VI = 15 11010 V2=17 11020 GOSUB 1430 Строка 1430 подпрограммы переместит курсор на строку VI. Строки 1450—1470 подпрограммы выведут в строки VI—V2 экрана по WIDE % пробелов. Строка 1480 вернет курсор в позицию с ко¬ ординатами VI, 1. Испытайте эту подпрограмму, объединив ее с программой, приведенной на рис. 4.9, изменив операторы INPUT в строках 30 и 40 на ввод переменных VI и V2 и изменив вызов подпрограммы в строке 100 на GOSUB 1430. ДОСТУП К ЭКРАНУ Работали ли вы когда-нибудь в системе разделения времени? Если работали, то, наверное, помните, как выдаваемые компьюте¬ ром сообщения почти все время сдвигались вверх по экрану. 114
Зайдите на кафедру или в лабораторию вычислительной техники и посмотрите на экран, когда студенты работают за терминалами. Изображение формируется построчно и все время сдвигается вверх. Если вы будете долго смотреть на экран, то у вас может начать кружиться голова. Если вы страдаете головокружением, ваше дело плохо. РАЗБИЕНИЕ НА КАДРЫ Те, кто начинал работать на ЭВМ во времена систем разде¬ ления времени, больших машин или незабвенного телетайпа, при¬ выкли к «перематывающемуся» по экрану изображению и часто считают его вполне приемлемым. Но если вы начали работать на компьютерах во времена микроЭВМ, то будете относиться к пере¬ мотке совсем по-другому. В большинстве хорошо написанных про¬ грамм вместо сдвига выдача разбивается на кадры. Под разбие¬ нием выдачи на кадры (страницы) имеется в виду формирование сразу всего изображения на экране, сверху донизу, с предвари¬ тельной его очисткой. Разбиение на кадры обеспечивает четкую границу между ста¬ рым и новым изображением. Оно меньше утомляет глаза. Сдвиг изображения утомляет зрение, заставляет фиксировать внимание на отдельных строках вместо более правильной ориента¬ ции на экран в целом и, насколько нам известно, может слу¬ жить признаком дурного характера программиста. На самом деле сдвиг, пожалуй, и не заслуживает столь резких слов, но все же лучше его избегать. Разбивать выдачу на страницы очень просто: достаточно очи¬ щать экран перед началом формирования каждого нового кадра. Делайте это с помощью оператора CLS, помещаемого в на¬ чало программного текста, порождающего кадр вывода. Действие этого оператора эквивалентно нажатию на клавиши Ctrl-Home. Он очищает экран и перемещает курсор в левый верхний угол. Очистив экран, выдавайте информацию. ПАУЗЫ МЕЖДУ КАДРАМИ Для смены кадров, как правило, требуются прямые действия пользователя. Некоторые демонстрационные программы выдают кадр в течение некоторого фиксированного времени, скажем 30 с, а затем стирают его и выдают следующий кадр. Но обычно после вывода кадра программа должна сделать паузу. Ее можно запрограммировать разными способами. Чаще всего паузы между кадрами не приходится создавать специально: они возникают при 115
ожидании ввода данных пользователем. Ввод подробно будет об¬ суждаться в гл. 5. Чтобы создать паузу, от пользователя часто требуют нажать на клавишу пробела или на некоторую другую клавишу. На рис. 4.12 приведена простая подпрограмма, которая в режиме инверсии выдает по центру 23-й строки такую фразу: [Для продолжения работы нажмите клавишу пробела] 0 REM Подпрограмма паузы 1 REM SAVE"A:FIG4-12" , А 4010 REM--Пауза-- 4020 LOCATE 23,WIDEZ/2-23 4030 COLOR 16, 7:REM режим мигающего инвертированного отображения 4040 PRINT"[Для продолжения работы нажмите клавишу пробела]"; 4050 COLOR 7,0:REM режим нормального отображения 4060 A|zINKEY|:IF Аф<>" " GOTO 4060 4070 PRINT 4080 RETURN Рис. 4.12. Подпрограмма, выводящая на экран подсказку: «[Для продолжения работы нажмите клавишу пробела]» и приостанавливающая работу программы до тех пор, пока эта клавиша не будет нажата Далее она ждет, пока пользователь не нажмет эту клавишу. Эта подпрограмма использовалась в одной из подпрограмм обра¬ ботки ошибок, описанных в предыдущей главе (см. рис. 3.12). Если в строке 4060 изменить помещенный в кавычки символ, то под¬ программа будет ждать нажатия другой клавиши. Рассматриваемая подпрограмма не имеет аргументов, и поль¬ зоваться ею крайне просто: достаточно вставить в то место про¬ граммы, где вы пожелаете сделать паузу, оператор GOSUB 4010. Тогда подпрограмма выдаст сообщение и будет ожидать, пока пользователь не нажмет нужную клавишу. Затем продолжится нормальная работа программы. ПАУЗЫ ОПРЕДЕЛЕННОЙ длительности Паузы часто организуют и другим способом — создавая за¬ держку на фиксированное время. На рис. 4.13 приведен листинг подпрограммы, создающей задержку примерно на ТХ секунд. Та¬ кие задержки можно вставлять между хелп-кадрами или между кадрами демонстрационных программ. Подберите длительность показа кадров, соответствующую их информационному содержа¬ нию (если информация сложна, то будет лучше, чтобы сменой кад¬ ров управлял пользователь). Для просмотра кадра размером 80Х Х25 символов обычно бывает достаточно 60 с (часто это даже слишком много). Организация задержки такой длительности осу¬ ществляется с помощью включения в программу операторов 116
ТХ = 60 и GOSUB 4100. При выполнении подпрограммы в строках 4110 и 4120 будет работать цикл FOR-NEXT, отвлекающий вни¬ мание компьютера примерно на ТХ секунд. 0 REM Подпрограмма задержки на ТХ секунд 1 REM SAVE”A:FIG4-13", А 4100 REH--Задержка на ТХ секунд-- 4110 FOR А =1 ТО ТХМ967 4120 NEXT 4130 RETURN Рис. 4.13. Подпрограмма, вызывающая за¬ держку на ТХ секунд Если вам нужен более точный отсчет времени, воспользуйтесь переменной' Т1МЕ$ языка Бейсик1. ПК следит за временем и каждую секунду обновляет строковую переменную Т1МЕ$. Вы сможете наблюдать, как это происходит, если наберете и запусти¬ те такую маленькую программу: 10 PRINT TIME$ 20 GOTO 10 Вы увидите, как, сдвигаясь вверх по экрану, будет выводить¬ ся время. Оно будет изменяться каждую секунду. Это время до¬ вольно точно, так как оно определяется внутренними часами ПК. Строковая переменная Т1МЕ$ имеет формат HH:MM:SS, где НН обозначает часы, ММ — минуты, a SS — секунды. Для определе¬ ния интересующей вас части переменной Т1МЕ$ можно восполь¬ зоваться функциями выделения подстрок. Например, для получе¬ ния секунд надо выделить подстроку, состоящую из двух крайних правых символов строки Т1МЕ$, и преобразовать ее в числовую форму с помощью функции VAL. Иначе говоря, воспользуйтесь таким выражением: SECONDS = VAL (RIGHT| (TIMEj, 2)) Для выделения НН и ММ можно воспользоваться функциями LEFT$ и MID$. Теперь вам будет довольно просто составить подпрограмму, обеспечивающую точный отсчет времени. КАК ПРОЕКТИРОВАТЬ ФОРМАТ КАДРА Кадры вывода можно спроектировать и хорошо, и плохо. Зна¬ ние всего нескольких простых правил может существенно улуч¬ шить результат вашей работы. В данном параграфе приводятся некоторые из этих правил, а также несколько примеров. 1 Если ваша программа предназначается для более или менее широкого использования, применяйте только этот метод отсчета времени: скорость работы различных компьютеров варьирует в широких пределах; например, IBM PC/AT работает в 5—7 раз быстрее, чем IBM PC.— Примеч. пер. 117
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |Т|2|3|4Г5Тб|7Т8|9|10|11|12|13|14|15|1б|17|18|19|20|21|22|23|24|25|2б|27|28|29|30|31|32|33|34|35|Зб|37|38|39|40| Рис. 4.14. Матрица для Конечно, все эти правила применимы в определенных грани¬ цах. Нарушение излагаемых правил не приведет вас за решетку, но сделает проектируемые вами кадры менее понятными и привлека¬ тельными. Иногда приводимые правила имеет смысл нарушить, но, как говорится, прежде чем нарушать закон, узнайте, в чем он состоит. ПОЛЬЗУЙТЕСЬ МАТРИЦЕЙ ПРОЕКТИРОВАНИЯ КАДРА На рис. 4.14 изображена матрица проектирования кадров раз¬ мером 80X25. На рис. 4.15 изображена матрица 40X25. Это очень полезные бланки. Они позволяют заранее спроектировать кадр вывода или печатный отчет с помощью карандаша на бумаге, и когда вы сядете за компьютер, вам останется только закодировать готовый проект. Столбцы (1—80) пронумерованы сверху и снизу, а строки (1 — 25) — с обеих сторон бланков, сверху вниз. Обратите внимание, что крайние справа столбцы (соответственно 80-й и 40-й) и ниж¬ няя строка (25) зачернены, напоминая, что в них не следует ничего выводить. Конечно, можно пользоваться и этим столбцом, и строкой, но в таком случае усложнится формирование кадра. Бейсик по собственной инициативе добавляет к выводимым дан- 118
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 6С 6И 52 I 63 I 541 551 56 < 57 i 68 I 69 70 71 72: 73 74 75 76 77 78 79|801 1 2^ 3 4 5 6 7 8 9 10 11 12 13 Г 14 15 16 17 18 19 20 21 * 22 23 I 24 проектирования кадров 80X25 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 зэЫ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 1 I2 I3 I 4 I 5 I6 |7 I8 I9 [l 0|7l| 12^Гз|14П5^^^ П ]20|2l|22 23 24 25 26 f27|28|29 зори 32|33р4|35|36 ]37|38 iwoj Рис. 4.15. Матрица для проектирования кадров 40X25 119
ным символ перевода строки. При выводе в строке 25 или столбце 80 какой-либо информации это вызовет либо сдвиг кадра вверх, либо лишний пробел. Перевод строки можно подавить, сопроводив оператор PRINT точкой с запятой, но безопаснее вообще не поль¬ зоваться последним столбцом и последней строкой. Кадры следует подготавливать на этапе планирования и про¬ ектирования программы. Их надо вначале разметить карандашом на бумаге, а потом уже реализовывать на экране дисплея. Кодирование должно превратиться в механический процесс пере¬ носа проекта кадров с бумаги в команды перемещения курсора и операторы PRINT. Отнесите рис. 4.14 (или рис. 4.15) в свою копировальную мастерскую и снимите с них копии в количестве, достаточном для дальнейшей работы. озаглавливайте кадры Как бы вы себя почувствовали, зайдя в книжный магазин и увидев, что все книги имеют голые обложки и титульные листы? Что вы скажете о конференции, где все носят над карманом пиджа¬ ка карточку с надписью: Привет! Моя фамилия Люди хотят знать, с кем или с чем они имеют дело. Так сообщайте им это! Даже если вам все очевидно, многим другим, возможно, и нет. Временами ориентацию теряют даже опытные пользователи — они встают из-за компьютера, выходят в другую комнату, смотрят по телевизору футбол или с кем-нибудь разго¬ варивают, а возвращаясь, забывают, что было изображено на экране. Вывод: помечайте каждый кадр, выводя в его верхней части заголовок. Рекомендую выводить его большими буквами в режи¬ ме инверсии. На рис. 4.16 изображена подпрограмма, которая выводит в режиме инверсии по центру строки заголовок. Аргументами этой подпрограммы служат переменные WIDE % (число столб¬ цов) и т| (текст заголовка). Например, при выполнении следу¬ ющих строк: 100 Т$ = «ЗАГОЛОВОК» 110 GOSUB 1500 120 END по центру строки черными буквами на светлом фоне будет выведе¬ но слово «ЗАГОЛОВОК». Подпрограмма ничего не стирает, а следовательно, с ее по¬ мощью можно расположить заголовок по центру любой строки 120
0 REM Подпрограмма центрирования и вывода заголовка 1 REM SAVE"A:FIG4-16" , А 1500 REM--Центрирование и вывод заголовка- 1510 Т=(WIDEZ+1-LEN(Ti))/2 1520 LOCATE ,T:REM позиционирование курсора по горизонтали 1530 COLOR 0,7:REM инверсия 1540 PRINT Т$ 1550 COLOR 7,0:REM нормальное отображение 1560 RETURN Рис. 4.16. Подпрограмма, выводящая заголовок кадра по центру строки экрана экрана. Для этого следует предварительно переместить курсор на эту строку. Если вы хотите выдать заголовок в верхней строке, то перед вызовом подпрограммы экран следует очистить с по¬ мощью оператора CLS. разделяйте кадр на логические области Выводимую на экран информацию обычно можно разбить на несколько классов. Каждому классу целесообразно отвести свою зону кадра, например: • заголовок кадра: выводится в центре верхней строки; • область данных: предназначена для выводимого текста, чи¬ сел, графиков и их сочетаний. Обычно располагается в средней части кадра; • область ввода: подсказки на ввод могут располагаться в любой части кадра — верхней, средней и нижней; • область управления: меню и подсказки управления могут располагаться в любой части экрана; • область сообщений: предупреждения, информацию о состоя¬ нии программы и прочие сообщения можно выводить в любом месте экрана. Перечислены лишь наиболее общие типы информации, выводи¬ мой на экран; этот список далеко не полон. Существует лишь одно неизменное правило расположения информации: заголовок должен размещаться наверху, а данные ниже. В остальном рас¬ положение данных на экране можно проектировать произволь¬ ным образом, лишь бы кадры были понятны и удобны поль¬ зователю. В большинстве программ фигурируют кадры нескольких фор¬ матов. Каждый формат предназначен для информации одного или нескольких классов. Последовательный подход к проектированию требует, чтобы в кадрах различных форматов были одинаково расположены области однотипных данных. Чтобы добиться этого, проанализируйте, какие форматы кадров нужны в вашей програм¬ ме. Определите также классы выдаваемой в них информации. 121
Затем подготовьте один или несколько макетов кадра и исполь¬ зуйте его как образец при проектировании конкретных кадров вывода. Определите минимальное число форматов (в идеале один), с помощью которых можно подготовить все кадры вашей программы. Рис. 4.17—4.19 иллюстрируют макеты кадров некоторой ги¬ потетической программы. Макет 1 (рис. 4.17) содержит главное меню. В рассматриваемой программе используется несколько раз¬ личных меню. Формат каждого из них аналогичен макету 1. Заголовок расположен сверху, варианты меню — в середине, а подсказка на выбор варианта — внизу. Макет 2 (рис. 4.18) изображает кадр ввода данных. Заголо¬ вок выводится в верхней части экрана, а пронумерованные поля данных — в середине. Нижняя часть кадра содержит меню, кото¬ рое позволяет добавлять, изменять и удалять введенные данные и завершать работу программы. Кроме того, в нижней части кадра располагается строка сообщений. Макет 3 (рис. 4.19) предназначен для кадров вывода, пред¬ ставляющих численные результаты. Заголовок находится в верх¬ ней части кадра. Подзаголовки, «шапки» столбцов и численная информация заполняют среднюю часть экрана. Нижняя его часть содержит меню, позволяющее выбрать следующий кадр или пре¬ кратить отображение результатов. Формат разрабатываемых макетов определяется вашей про¬ граммой. Для обеспечения однотипности кадров не отступайте от разработанных макетов при кодировании. Конечно, возможны и исключения. Не подгоняйте искусственно все программы под одну схему. Последовательность очень важна, но все же основное назначение каждого кадра — приносить поль¬ зу: передавать информацию, управлять программой, принимать вводимые данные и т. п. Если в одном кадре выводится информация нескольких типов, помещайте ее в разные зоны и снабжайте соответствующие об¬ ласти экрана заголовками: иначе пользователю будет трудно разо¬ браться в том, что изображено на экране. Это утверждение лучше всего обосновать примером. На рис. 4.20 изображен плохо спроек¬ тированный кадр, имеющий следующие недостатки: • кадр не озаглавлен; • выделены три области данных, но неясно, где их границы; • шапками столбцов служат непонятные сокращения; • подсказки (нижняя строка кадра) неясны; • шапки и подсказки трудно отличить от данных. На рис. 4.21 изображено, как следовало бы спроектировать предыдущий кадр. Обратите внимание на различия: © кадр озаглавлен; © средняя часть кадра разделена линиями на три области дан¬ ных. Каждая из них также озаглавлена; 122
Рис. 4.18. Гипотетический формат кадра ввода данных 123
РЕЗУЛЬТАТЫ Первый набор данных Второй н абор данных Изделие Стоимость Изделие Стоимость А1 А2 В1 В2 С1 С2 Z1 Z2 Рис. 4.19. Гипотетический формат кадра, в котором сообщаются численные результаты работы программы ELECTRIC LIGHT & POWER COCT: AKTB 1/8 1/8 КОЛ 4680 9120 ДТ 21/3-85 22/3-85 ЦН 11 и 12 и Рис. 4.20. Пример плохо спроектированного кадра. Нет заголовков, области данных перекрывают друг друга, «шапки» трудно отличить от данных, а сокращения и подсказки неясны 124
{ЗАПИСЬ ОБ ОПЕРАЦИИ]"^ ДАННЫЕ О ФАЙЛЕ [НАИМЕНОВАНИЕ!: ДАННЫЕ ОБ АКЦИЯХ IHOMEPl :4 [данные О ЗАПИСЙ1 iHOMEPl : 116 [НАЗВАНИЕ АКЦИИ1: ELECTRIC LIGHT & POWER 1СОСТОЯНИЕ1 : АКТИВНОЕ [дата I 21/03-85 22/03-85 29/03-85 31/03-85 [история активности] ГЦЕНА[ |КОЛИЧЁСТВО| 11 и 1 /8 4680 12 и 1/8 9120 22 и 1 /2 13460 22 и 1/8 22410 п о ESC - ПЕРЕЛИСТНУТЬ СТРАНИЦУ ИСТОРИИ - ПЕРЕЛИСТНУТЬ ЕЕ ОБРАТНО - ЗАВЕРШИТЬ РАБОТУ Рис. 4.21. Улучшенная версия кадра, изображенного на рис. 4.20. Есть заголовки, области данных отделены друг от друга, вместо сокращений используются полные слова, а подсказка понятна • шапками столбцов служат не сокращения, а полные слова; • подсказки ясны и понятны; Ф заголовки и подсказки выводятся в режиме инверсии и хо¬ рошо выделяются из прочих данных. Несколько небольших изменений существенно улучшили дело. Заголовки, шапки и подсказки не обязательно отображать в режиме инверсии, но они всегда должны быть выделены. Вместо инверсии их можно было бы вывести подчеркнутыми, с повышен¬ ной яркостью или заключенными в рамку. Старайтесь не пользоваться сокращениями. Многие програм¬ мисты полагают, что так или иначе все ожидают от компьютера сокращений и что сокращения легко понимать. Что касается первого утверждения, они, пожалуй, и правы, но относительно вто¬ рого — ошибаются. Сокращения менее понятны, чем полные сло¬ ва. Поэтому избегайте их. Есть разные способы разделения области данных на зоны. На рис. 4.21 по границе зон проведены линии. Но области можно раз¬ делить и пробелами (не менее двух). Третий способ использует цвет. Разделите экран на блоки и в каждом из них воспользуй¬ тесь другим цветом фона (символов). Хотя такой способ выделе¬ ния зон кадра труднее программировать, вам не понадобятся раз¬ делители между зонами, которые занимают место на экране: раз¬ 125
ные зоны и без того будут ясно выделяться своим цветом. Цвета надо подбирать так, чтобы различные блоки имели примерно оди¬ наковую яркость; иначе пользователю придется адаптироваться к разным уровням яркости на одном экране. Наихудший вариант— выводить в некоторых зонах черные символы на светлом фоне, а в других — белые на черном. КАК ОТОБРАЖАТЬ ТЕКСТ Текст состоит из слов, объединенных в предложения. В про¬ грамме текст может использоваться по-разному, например для: • письменных указаний; • сообщений об ошибках; • предупреждений; • пояснений; • описаний; • определений. Приведем правила вывода текста на экран. • Пользуйтесь и прописными, и строчными буквами, а не только прописными. • Избегайте переноса слов со строки на строку. По крайней мере не допускайте механического переноса слов на следую¬ щую строку. • Избегайте сокращений и профессионального жаргона. • Пишите простым, ясным языком, употребляя общеприня¬ тые слова. • Чтобы длинные тексты было легче читать, разбивайте их на короткие абзацы. • При выдаче описаний процедур и указаний перечисляйте их шаги в том порядке, в котором они выполняются. Не сос¬ тавляйте описания в форме сплошного длинного текста. • Выводите текст таким цветом и на таком фоне, которые не утомляют глаза. • Управление скоростью вывода текста предоставьте пользо¬ вателю. Если в программе надо вывести несколько страниц текста, то их «перелистыванием» можно управлять, нажи¬ мая клавишу «Пробел» или «Ввод». Никогда не управляйте перелистыванием «с помощью секундомера», т. е. не застав¬ ляйте пользователя читать с той скоростью, которую уста¬ новит программа. Текст, в котором по обычным правилам употребляются и про писные, и строчные буквы, воспринимается легче, чем текст, на¬ писанный только большими буквами. Многие программисты при¬ выкли работать с прописными буквами и, не задумываясь, поль¬ зуются ими при составлении текстов — как по старой привычке за¬ полняют экран сокращениями и профессиональными терминами. И то и другое малопонятно пользователю. Будет правильнее 126
пользоваться богатым естественным языком, избегать сокращений и жаргона и не забывать, что существуют не только большие, но и малые буквы. КАК ПРЕДСТАВЛЯТЬ НА ЭКРАНЕ ЧИСЛА Как только что отмечалось, при выводе на экран дисплея текста его выравнивают влево, т. е. сдвигают все строки к некоторому ле¬ вому полю. При выводе чисел следуют другому соглашению: числа выравнивают по десятичной точке (рис. 4.22). Кроме того, их обычно выдают с одинаковым количеством значащих цифр справа от десятичной точки. Выравнивание чисел по десятичной точке иногда называют «^-форматизацией», поскольку этот прием широ¬ ко используется при выводе столбцов денежных величин. Таким образом, например, форматизируют различные счета и высылае¬ мые банками справки об учете чеков. Это соглашение соблюдает¬ ся при выводе различных численных величин, не обязательно денежных. Выравнивание чисел по десятичной точке облегчает их чтение. Сравните, например, рис. 4.22 (числа |-форматизированы) и 4.23 (числа не форматизированы) и задайте себе такие вопросы: какой рисунок лучше выглядит, в котором из них вы быстрее смо¬ жете найти самое большое и самое малое, числа? Наборы связанных между собой чисел обычно не только вырав¬ ниваются по десятичной точке, но и выводятся в один столбец под заголовком, сообщающим, что эти числа собой представляют. Ни¬ когда не выводите набор чисел в строку (рис. 4.24). Если вы выводите одно число, то выводите совместно с ним и наименование (слева от числа) и разделяйте их двоеточием, на¬ пример: ЦЕНА: 105.16 Так же поступайте при выводе ряда не связанных между собой чисел. Итак, вывод чисел подчиняется двум соглашениям. • Список чисел выводится в столбец, с «шапкой» наверху и выравнивается по десятичной точке. • Отдельное число выводится в таком порядке: наименова¬ ние, двоеточие, пробел и само число. Числа легко форматизировать с помощью оператора PRINT USING. Этот оператор позволяет задать формат вывода. Формат определяется некоторой строкой символов. Например, вывод числа с двумя значащими цифрами после десятичной точки задается строкой «ф # #», Еде каждый символ # представляет одну позицию цифры слева или справа от десятичной точки. Иначе 127
Рис. 4.22. Столбец чисел выравнен по десятичной точке. Числовую информацию следует представлять именно так Рис. 4.23. Числа выравнены влево — числовая информация пред¬ ставлена неправильно, ее неудобно читать 128
Рис. 4.24. Числа выведены на экран в строку, как текст. Такой вывод неудобен для представления числовой информации говоря, для вывода и форматизации числа X используется такой оператор: PRINT USING X Если один и тот же формат используется многократно, то це¬ лесообразно определить строковую переменную, содержащую формат вывода: тогда текст операторов PRINT USING станет бо¬ лее компактным. Например, мы можем включить в программу такие строковые константы: 10 20 30 Теперь для вывода переменных с одной, двумя или тремя знача¬ щими цифрами после запятой можно воспользоваться ранее опре¬ деленными строками. Так, для вывода двух значащих цифр после запятой можно воспользоваться строкой С2$, т. е. написать такой оператор: PRINT USING С2$; X Мы привели только самые поверхностные сведения о возмож¬ ностях оператора PRINT USING. Эта тема детально разбирается в руководстве фирмы IBM по языку Бейсик. За подробностями обра¬ щайтесь к этому руководству. 5 Зак. 1488 129
ПРОЕКТИРОВАНИЕ ПЕЧАТНЫХ ОТЧЕТОВ Печатным отчетом называется создаваемая компьютером рас¬ печатка на бумаге. Отчет может содержать текст, числа и графики в любом сочетании. Распечатка имеет два преимущества перед выдачей на экран. Во-первых, она существует постоянно, а не исчезает при выключении компьютера. Во-вторых, она может иметь любую длину. Вы не ограничены узким окном дисплея. Главный недостаток печатных отчетов заключается в их отры¬ ве от того контекста, в котором они создавались. Любой кадр вывода воспринимается в связи с кадрами, появлявшимися ранее, и тем способом, которым пользователь привел программу в данное состояние. Но, приступая к работе с распечаткой, пользо¬ ватель может и не знать истории ее создания. Печатный отчет мож¬ но сравнить с вырванной из книги страницей. По этой причине четко идентифицируйте отчеты. Снабжайте заголовком каждый отчет и различные его разделы. В отчеты часто оказывается необходимым включать такие сведе¬ ния, которые вы не стали бы помещать в кадр вывода, например дату его создания. Работая на ЭВМ, вы знаете дату, но, вытас¬ кивая из подшивки старый отчет о бюджете, вы можете и не знать, когда он был составлен. Основной вывод: необходимо учитывать влияние времени на интерпретацию отчета. Что понадобится знать пользователю? Ве¬ роятно, кто и когда составил отчет, некоторые условия состав¬ ления и т. п. Решать, что включать в отчет, придется вам. Большинство приведенных в данной главе указаний по проек¬ тированию кадров вывода относятся и к проектированию печатных отчетов. Напомним основные правила. • Снабжайте заголовками сам отчет и его разделы. • Разделяйте отчет на логические области. • При представлении текста пользуйтесь как прописными, так и строчными буквами и избегайте профессионального жаргона и сокращений. Пишите просто, ясно, применяя общеупотребительные слова. Разбивайте длинные тексты на короткие абзацы и параграфы. Процедуры представ¬ ляйте в форме перечисления их шагов. • При представлении чисел оставляйте между столбцами не менее двух пробелов. Выравнивайте числа в столбцах по десятичной точке. • До начала кодирования отчетов тщательно спланируйте их с помощью матрицы проектирования (см. рис. 4.14). На рис. 4.25 изображена предназначенная для принтера вер¬ сия подпрограммы центрирования и вывода заголовка (см. рис. 4.16). Аргументами новой подпрограммы служат переменные PWIDE% (число печатаемых принтером столбцов) и Т$ (текст заголовка). Если ваш принтер всегда печатает 80 или другое по- 130
0 REM Подпрограмма центрирования и вывода заголовка (на принтер) 1 REM SAVE”А:FIG4-25” , А 1600 REM--Центрирование и вывод заголовка (на принтер)-- 1610 Т=(PWIDEZ+1-LEN(Т|))/2 1620 LPRINT ТАВ(Т) Т| 1630 RETURN Рис. 4.25. Подпрограмма центрирования и печати заголовка на принтере стоянное число столбцов, то замените PWIDE% на эту констан¬ ту. Пользоваться рассматриваемой подпрограммой очень просто. Задайте аргументы, а затем выполните оператор GOSUB 1600. Указанный вами текст будет напечатан по центру строки отчета.
Глава 5 ВВОД, КОНТРОЛЬ ДАННЫХ И ПОДТВЕРЖДЕНИЕ ИХ ПРАВИЛЬНОСТИ Оператор INPUT — один из самых первых операторов, усваи¬ ваемых начинающим программистом. Оператором INPUT легко пользоваться, и большинство программистов овладевают им в совершенстве за несколько часов. Только позднее они осознают, что прием данных от пользователя вовсе не сводится к этому про¬ стому оператору. И дело не только в том, что сигнал о нажатии на клавишу можно воспринимать, не пользуясь оператором INPUT, например через переменную INKEY^. Гораздо существеннее, что при вводе данных каждый раз возникает множество обстоя¬ тельств, затрудняющих работу программиста. Прежде всего пользователь не всегда достаточно ясно пони¬ мает, что ему следует вводить. Возможно, ему непонятны сочи¬ ненные программистом подсказки или он просто не читал руковод¬ ство по работе с программой. В затруднении пользователь спосо¬ бен ввести такое сообщение, которое программист не смог бы пред¬ ставить даже в кошмарном сне. Пользователь может нажать на клавишу «Ввод», ничего не набрав, ввести цифры там, где должны быть буквы, или наоборот, изобрести свой собственный синтак¬ сис для записи дат, времени и телефонных номеров или каким-то другим способом разрушить стройный и упорядоченный взгляд программиста на окружающий мир. Столкнувшись с такими слу¬ чаями, программист быстро умнеет. Ему становится ясно, что для правильного программирования ввода данных недостаточно написать оператор INPUT. Но что ему следует делать? Прежде всего необходимо позаботиться о хороших подсказках. Получая хорошие подсказки, пользователь реже ошибается при вводе данных. Но одних подсказок мало. Поскольку ошибки в вводимых данных продолжают время от времени встречаться, программист осознает, что все, что вводит пользователь, нуждается в проверке. Ни один программист не может предвидеть все возможные ошибки, тем более он не может написать выявляющий их программный текст. Программист убеждается в том, что проверять входные данные на наличие оши¬ бок намного сложнее, чем применять операторы языка BASIC, пре¬ образующие сигналы нажатия на клавишу в значения перемен¬ ных, хранящихся в памяти компьютера. 132
После того как он научится контролировать данные, перед ним встают новые проблемы. Введя некоторую порцию данных, пользо- вательнередкозамечает в них ошибку или решает их изменить. Не опоздал ли он? Не будет ли лучше предоставить пользователю возможность исправить введенные данные, например, повторив их ввод? В настоящей главе я пытаюсь дать разумные ответы на эти и связанные с ними вопросы. Слово «разумные» уместно, поскольку невозможно ни написать подсказки, которые правильно поймут все пользователи, ни защититься от всех возможных ошибок, ни выполнить все причуды пользователей. Все имеет свои пределы. Но удовлетворить значительную часть требований возможно, а большего и не следует ожидать от достаточно ответственно отно¬ сящегося к своему делу программиста. В начале главы обсуждаются операторы ввода данных: INPUT, LINE INPUT и INKEY$. Затем рассматриваются различные этапы процесса ввода данных, описываются применяемые на этих этапах приемы программирования и приводятся примеры — фрагменты программного текста и целые подпрограммы. Далее излагаются методы выдачи информации на экран в процедурах ввода данных. ОПЕРАТОРЫ ВВОДА ДАННЫХ ПК может принимать данные с клавиатуры различными'спосо¬ бами. Чаще всего это делается с помощью операторов INPUT, LINE INPUT и INKEY$. Но можно воспользоваться и оператора¬ ми INPUT$, INPUT# и LINE INPUT#, которые обычно приме¬ няются для чтения данных из файлов. Последние операторы не выдают вводимые данные на экран дисплея и поэтому, как пра¬ вило, не применяются для ввода данных с клавиатуры (за исключе¬ нием, пожалуй, их использования в процедурах ввода пароля). Поэтому в дальнейшем мы будем обсуждать только три наиболее широко используемых оператора ввода данных. Эти операторы имеют различные характеристики и поэтому будут рассматри¬ ваться в отдельных параграфах. ОПЕРАТОР INPUT Приведем основные характеристики оператора INPUT. • Для привлечения внимания на экран выдается мигающий курсор. • Оператор может использоваться для приема длинных сообщений. • Пользователь может изменять вводимые данные (до подт¬ верждения) и подтверждать их нажатием на клавишу «Ввод». 133
• При неправильном вводе данных пользователь может иска¬ зить кадр вывода. Если, например, за оператором INPUT следует имя действительной переменной (скажем, INPUT А), а пользователь наберет букву и нажмет клави¬ шу «Ввод», то на экране появится сообщение «Redo from start» («Начните сначала»), и кадр сдвинется на одну строку вверх. Сдвиг изображения произойдет и в том слу¬ чае, если пользователь введет запятую или слишком длин¬ ную строку символов. • Оператор INPUT допускает вывод подсказки, появляю¬ щейся на экране при его выполнении. Например, оператор INPUT “Фамилия:“^А$ выведет на экран слово «Фами¬ лия», за которым будут следовать знак вопроса и мигаю¬ щий курсор. Это изображено в следующей строке: Фамилия: ? Вопросительный знак можно убрать, поставив перед именем переменной, которой присваивается значение, за¬ пятую (вместо точки с запятой). Например, оператор INPUT “Фамилия/4 , NA$, выдаст такую подсказку: Фамилия: ОПЕРАТОР LINE INPUT Оператор LINE INPUT работает аналогично оператору INPUT, но, в отличие от последнего, позволяет пользователям вводить любые данные, включая запятую и знак кавычки. Благода¬ ря этому оператор LINE INPUT во многих случаях имеет пре¬ имущество над оператором INPUT, рассматривающим запятую как признак конца вводимых данных. Чтобы убедиться в этом, на¬ берите и запустите следующую маленькую программу: 10 INPUT А$ 20 PRINT А$ В ответ на подсказку наберите какой-нибудь текст, содержа¬ щий запятую, например «Кузнецов, Петр Алексеевич», и посмотри¬ те, что произойдет. Теперь замените оператор INPUT на LINE INPUT и сделайте то же самое. Оператор LINE INPUT менее требователен к принимаемым им данным, поэтому его следует предпочесть оператору INPUT. ОПЕРАТОР INKEYS Приведем основные характеристики оператора INKEY$. • Оператор INKEY$ не создает на экране подсказки в виде мигающего курсора или знака вопроса. Однако мигающий курсор можно изобразить с помощью оператора COLOR. 134
• За одно обращение к оператору INKEY| принимается один символ. • Набираемые символы не появляются на экране (нет эха). • Пользователь не может проверять набранные данные. Сим¬ вол вводится в компьютер и присваивается соответствую¬ щей переменной, как только на клавиатуре будет нажата какая-нибудь клавиша. Оператор INKEY$ — это также оператор ввода данных, но со¬ вершенно иного типа, чем операторы INPUT и LINE INPUT. Он воспринимает отдельное нажатие на клавишу и не требует, что¬ бы в подтверждение набранных данных пользователь нажимал клавишу «Ввод». Может показаться, что «голый» оператор INKEY$ в большинстве случаев будет бесполезен: ведь он не по¬ рождает ни мигающего курсора, ни копии вводимых данных на экране. Не будем все же спешить с выводами. Существуют три модели оператора INKEY$, которые можно сравнить с различными модификациями автомобиля одной марки. Рассмотрим эти модели: «Голый», или «самый дешевый» INKEY$. Это простейшая фор¬ ма оператора. Приведем пример того, как его можно использо¬ вать: 10 PRINT ”Вы согласны? (д/н):”; 20 A$=INKEY$:IF А$=” ” GOTO 20 30 IF А$<>”д” AND А$<>”н” GOTO 20 Эта маленькая программа применяется для подтверждения результата, который был выдан пользователю на экран. Если поль¬ зователь согласен с результатом, то он нажимает клавишу «д». В противном случае нажимается клавиша «н». Строка 10 программы выводит подсказку, строка 20 содержит цикл опроса клавиатуры оператором INKEY$, а строка 30 выполняет проверку и повторяет эту процедуру до тех пор, пока не будет набран правильный ответ («д» или «н»). В этой простейшей ситуации мигающий курсор на экране не появляется, а набранная буква не выводится. Если бы это было сделано, процедура стала бы лучше, но в столь простом случае такие дополнительные возможности несуществен¬ ны. . «Улучшенный» INKEY$. В отличие от предыдущей модели улучшенный INKEY| выдает мигающий курсор и выводит наби¬ раемые данные на экран. Для этого в программу достаточно добавить всего три строки текста. Новый текст будет выглядеть следующим образом: 10 PRINT ”Вы согласны’? (д/н): 15 COLOR 23,0: PRINT ” :REM мигающий курсор 16 COLOR 7,6: REM режим нормального отображения 20 A$=INKEY$:IF А$ ” ” GOTO 20 30 IF А$ < > ”д” AND А$ < > ”н” GOTO 20 40 LOCATE, POS(O) — 1: PRINT A$; :REM выдать введенный символ 135
В программу добавлены строки 15, 16 и 40. Строка 15 устанав¬ ливает режим мигающего изображения и выводит символ подчер¬ кивания, который похож на курсор. Строка 16 восстанавливает режим нормального отображения. Строка 40 определяет положе¬ ние курсора (сразу после мигающего знака подчеркивания), возвращает его на одну позицию и выводит на этом месте введен¬ ный с клавиатуры символ. Обратите внимание, что этот символ выдается только в том случае, если он является строчной буквой «д» или «н»: прочие символы отфильтровываются в строке 30. . INKEY$ «люкс». В дополнение ко всему, что делает «улучшен¬ ный» INKEY$, INKEY^ «люкс» позволяет вводить сообщения, со¬ стоящие из нескольких букв. Он допускает ввод запятых, дает возможность отфильтровывать вводимые пользователем символы, игнорируя некоторые из них, и ограничивает длину вводимых строк по максимуму и минимуму. Оператор 1NKEY$ мощнее, чем операторы INPUT и LINE INPUT, и в некоторых программах может их заменять. С помощью оператора INKEY$ этой модификации можно соз¬ давать полные кадры ввода типа того, что изображен на рис. 5.1. Подобные кадры содержат несколько полей, и пользователь вводит КАДР ВВОДА ДАННЫХ адрес ПОЧТОВЫЙ ИНДЕКС ГОРОД УЛИЦА НОМЕР ДОМА (МЕЖДУГОРОДНОЙ СВЯЗИ) НОМЕР Рис. 5.1. Кадр ввода данных. Все подсказки выведены на экран заранее и по мере того, как пользователь вводит данные, курсор перемещается от поля к полю 136
1. ПЕРЕМЕЩЕНИЕ КУРСОРА НА НАЧАЛО ПОДСКАЗКИ 2. ВЫДАЧА ПОДСКАЗКИ т 10050 10060 3. ПЕРЕМЕЩЕНИЕ КУРСОРА 4 10090 г 4. ВЫВОД РАНЕЕ ВВЕДЕННЫХ ДАННЫХ (А$) ~ Г 10100 5. МИГАЮЩИЙ КУРСОР 10110 4 6. INKEY$ В$ 4- 10130 НЕТ 10140 ДА дд Выход из прог - раммы 8С. A$=LEFT$ (А$, LEN (А$) -1 LEN (AS)=LMAX? т 10290 > Филыт) клавиатуры Клавиша DEL или курсор влево? $=CHR$(13)? клавиша "ВВОД") LEN (AS) > LMIN? 10190 Т 10250 1 8D. СТЕРЕТЬ ПОЛЕ ВВОДА ДАННЫХ I , I Запятая: ASC (В$)=44ГК или' Цифра: 47<ASC(B$) <58 или Буква: 64<ASC(B$) <91 \ ИЛИ / Пробел:ч ASC(B$)=32 10360 11. А$ = А$ + В$ Рис. 5.2. Блок-схема, демонстрирующая логику процедуры ввода данных I NKEY$ «ЛЮКС» 137
данные в эти поля поочередно. По завершении заполнения пер¬ вого поля курсор перемещается во второе, третье поле и т. д. Рабо¬ тая с такого рода кадрами, надо уметь управлять вводом данных; в противном случае достаточно несколько раз неудачно нажать на клавиши, чтобы на экране возникла совершенно непонятная меша¬ нина. Текст процедуры INKEY| «люкс» несколько запутан, поэтому ее работу легче всего описать с помощью блок-схемы. Мы вначале разберем блок-схему, а потом рассмотрим сам текст процедуры. Используя оператор INKEY$, программа должна принимать данные посимвольно. Затем введенные знаки сцепляются в одну длинную строку. Но не со всеми символами следует обращаться одинаково. Так, нажатие клавиши «Ввод» (CHRS(13)) сигнали¬ зирует о конце вводимых данных. Нажатие клавиш «Del» (удале¬ ние) или «Курсор влево» означает, что из уже введенных данных следует удалить один символ. Кроме того, программа может иг¬ норировать некоторые символы. На рис. 5.2 изображена блок-схема, демонстрирующая логику INKEY$ «люкс». Каждый шаг процедуры пронумерован. Его но¬ мер проставлен слева от соответствующего символа блок-схемы. Справа от символа стоит номер строки текста на языке BASIC, с которой начинается этот шаг. Сам текст процедуры приведен на рис. 5.3. Как на блок-схеме, так и в листинге введенная часть дан¬ ных хранится в строке А$, а принимаемый оператором INKEY$ символ помещается в строку В$. Шаг1: курсор перемещается в заданную позицию экрана. Шаг 2: выдается подсказка на дисплей. На блок-схеме к соот¬ ветствующим прямоугольникам не подходит ни одна стрелка, на¬ правленная вверх, а следовательно, можно вначале заполнить под¬ сказками весь кадр, а затем выполнить шаги 3—11 для каждого вводимого показателя по отдельности. Шаг 3: курсор перемещается в другую позицию, к концу под¬ сказки и в начало поля вводимого показателя. Шаг 4: на экран выводятся все символы, которые были введены до этого момента. Отметим, что каждый раз, как нажимается очередная клавиша, на экран выводится вся последовательность введенных символов. Это нужно для удаления символа и возврата курсора на одну позицию, о чем мы поговорим подробнее, когда будем рассматривать шаг 8. Шаг 5: на экран выводится мигающий курсор. Шаг 6: с помощью оператора INKEY^ в компьютер вводится один символ. Шаг 7А: проверяется, не была ли нажата клавиша «Ввод». Если клавиша была нажата, то на шаге 7В длина введенной последовательности символов (А$) сравнивается с допустимым минимумом (Lmin). Lmin может быть задан равным любой величи¬ не, не превышающей Lmax (максимальной длины), в частности 138
нулю. Но, как правило, желательно, чтобы вводился по меньшей мере один символ (Lmin= 1). Если длина введенной строки мень¬ ше минимально допустимой, то управление возвращается на шаг 6, где вводится следующий символ. В противном случае процедура^ заканчивает свою работу. Шаг 8А: проверяется, не была ли нажата клавиша «Del» или «Курсор влево». Если клавиша была нажата, то на шаге 8В уточ¬ няется, не пуста ли строка А|. Если она не пуста, то на шаге 8С из строки А| удаляется крайний правый символ. Затем на шаге 8D стирается поле вводимых данных, чтобы после повторного вывода 0 REM Процедура ввода данных оператором INKEYi типа ’’Люкс” 1 REM SAVE"A:FIG5-3",А 980 WIDEZ=80 990 GOTO 10000 1300 REM--Очистить одну строку-- 1310 LOCATE V,Н:REM переместить курсор в требуемую позицию 1320 PRINT SPACE|(WIDEZ+1-Н);:REM стереть все до конца строки 1330 LOCATE V, H:REM вернуть курсор в требуемую позицию 1340 RETURN 10000 REM--Процедура ввода данных оператором INKEY$ типа "Люкс"-- 10010 L1 = 1:.REM устанавливаем минимальную длину 10020 L2=12:REM устанавливаем максимальную длину 10030 A|="":REM инициализируем входную строку 10040 CLSrREM очищаем экран 10050 V;10:Н=1:GOSUB 1300:REM стираем строку и определяем место для подсказки 10060 COLOR 0,7:REM инверсия 10070 PRINT*фамилия (до 12-ти символов):"; 10080 COLOR 7,0:REM нормальное отображение 10090 LOCATE 10, 30 10100 PRINT А$;:REM выводим на экран введенные с клавиатуры данные 10110 COLOR 23,0:PRINT REM вспыхивающий курсор 10120 COLOR 7,0:REM нормальное отображение 10130 B$=INKEY$:IF Вф = «" GOTO -10130 10140 REM--Нажата ли клавиша ^Ввод*?-- 10150 IF ВфоСНИф (1 3’) GOTO 10190 10160 IF LEN(A$)<L1 THEN BEEP:GOTO 10130:REM проверка на минимальную длину 10170 PRINT 10180 END:REM конец входных данных 10190 REM--Не нажата ли клавиша "Удалить" или "Курсор влево"? 102Г00 IF LER(B$) = 1 GOTO 10270 10210 B1| = RIGHT|(B$, 1) 10220 IF В1ф<>"К" AND B1|O"S" GOTO 10270 10230 IF LEH(A|)=0 GOTO 10130:REM проверка на минимальную длину 10240 A$ = LEFT|(Аф, LEN(Аф)-1):REM удаление из строки Аф крайнего справа символа 10250 V=10:Н=30:GOSUB 1300:REM стираем введенные символы 10260 GOTO 10090 10270 REM--Проверка на максимальную длину-- 10280 IF LEN(A$)=L2 THEN BEEP:GOTO 10130 10290 REM--фильтр-- 10300 IF. АЗС(Вф)=44 GOTO 10360:REM введена запятая 10310 IF ASC(Bi)>47 AND ASC(B$)<58 GOTO 10360:REM цифра 10320 IF ASC(B$)>64 AND ASC(B$)<123 GOTO 10360:REM буква (латинская) 10330 IF АЗС(Вф)=32 GOTO 10360:REM пробел 10340 BEEP 10350 GOTO 10130 10360 Аф=Аф+Вф 10370 GOTO 10090 Рис. 5.3. Процедура ввода данных INKEY5 «люкс», соответствующая схеме, изображенной на рис. 5.2. 139
строки на шаге 4 на экране не оставалось удаленного символа. Шаг 9: проверяется, не равна ли длина строки А$ величине Lmax. Если равна, то управление возвращается на шаг 7. Оттуда управление будет передано на шаг 7 и шаги 7—9 будут повторять¬ ся до тех пор, пока не будет нажата клавиша «Ввод» или из не будет удален символ. Шаг 10: введенный символ пропускается через фильтр. Прове¬ ряется, удовлетворяет ли он установленным ограничениям: допустимыми считаются буквы (латинские), цифры, запятая и знак пробела. Если символ не пройдет проверки, управление будет возвращено на шаг 6. В результате символы, не соот¬ ветствующие установленным ограничениям , не будут восприни¬ маться программой. Шаг 11: введенный символ В^ сцепляется со строкой Ар, со¬ держащей ранее введенные символы. Рассмотрим теперь текст программы, выполняющей все эти «чу¬ деса». На рис. 5.3 изображена распечатка только что описанной процедуры INKEYJp «люкс». Обратите внимание, что в ней исполь¬ зуется подпрограмма стирания строки, приведенная в гл. 4. Эта подпрограмма применяется для позиционирования курсора и сти¬ рания строки, в которую будет выведена подсказка. Текст процедуры содержится в строках 10000—10370. Вам мо¬ жет показаться, что эта процедура громоздка, а заменяет лишь один простой оператор INPUT. В таком случае вам следует осознать, что эта процедура и делает гораздо больше, чем упомяну¬ тый оператор.' В строках 10010—10020 задается минимальная (L1) и макси¬ мальная (L2) длина строки Аэ. В строке 10030 А$ присваивается начальное значение. Строка 10040 очищает экран. Строка 10050 с помощью подпрограммы стирания строки перемещает курсор в столбец 1 строку 10. Строка 10060 включает режим инверсии отображения, а строка 10070 выводит подсказку — приглашение к вводу данных. В этой подсказке указывается, что максимальная длина фамилии равна 12 символам (значение переменной L2). Затем строка 10080 вос¬ станавливает режим нормального отображения. Строка 10090 перемещает курсор в столбец 30 строку 10. Затем строка 10100 выводит на экран А|, т. е. введенную к этому момен¬ ту часть данных. Строка 10110 выдает мигающий курсор, а строка 10120 восстанавливает режим нормального отображения. Строка 10130 содержит цикл, в котором оператор INKEY> при¬ нимает с клавиатуры один символ. В строке 10150 проверяется, не была ли нажата клавиша «Ввод», строки 10160 и 10170 выпол¬ няются только в том случае, если была нажата эта клавиша. В противном случае управление передается на строку 10190. В строке 10160 проверяется, удовлетворяет ли А$ ограничению по миниму¬ му длины; если это условие не выполняется, то подается звуко¬ 140
вой сигнал и управление возвращается на строку 10130, где с помощью оператора INKEY| вводится следующий символ. В дан¬ ном тексте строка 10170 содержит оператор PRINT, обеспечиваю¬ щий возврат каретки после выдачи А$, а следующая строка содер¬ жит оператор END. В реальной программе оператор END следует заменить на оператор GOTO, передающий управление на ввод следующего показателя. Если была нажата клавиша «Del» или «Курсор влево», то стро¬ ки 10190—10260 удаляют символ из строки А$. То, что делается в этих строках, не очевидно и требует пояснения. Клавишам Del и «Курсор влево» не соответствуют никакие шифры в коде ASCII, поэтому сигнал о нажатии на эти клавиши не может быть обна¬ ружен обычным способом. Однако им соответствуют шифры рас¬ ширенного кода ASCII. При нажатии на эти клавиши оператор INKEY$ возвращает не один, а два символа. Первый из них всегда является пробелом, а шифр второго символа в коде ASCII равен коду сканирования соответствующей клавиши (см. главу 3). Код сканирования клавиши «Курсор влево» равен 75, а код клавиши «Del» равен 83. В коде ACSII этим шифрам соответствуют буквы К и S (см. приложение В). Удаление символов осуществляется следующим образом: стро¬ ка 10200 определяет длину только что введенной (оператором INKEY|) символьной строки в$. Если ее длина равна 1, то В$ не может соответствовать ни клавиша «Del», ни клавиша «Курсор влево», и управление передается на строку 10270. В противном случае управление передается на строку 10210, в которой выде¬ ляется правый символ строки В$. Строка 10220 проверяет, не яв¬ ляется ли этот символ буквой К или S. Если это не так, т. е. если не была нажата ни клавиша «Del», ни клавиша «Курсор влево», то управление передается на строку 10270, а если была на¬ жата одна из этих клавиш, то управление перейдет на стро¬ ку 10230. Строка 10230 проверяет, не равна ли длина строки А$ нулю. Если длина этой строки равна нулю, то она пуста, удаление из нее невозможно, и управление возвращается строке 10130, на ввод сле¬ дующего символа. В противном случае строка 10240 удалит из строки А$ крайний правый символ, строка 10250 сотрет с экрана поле ввода данных, и управление будет возвращено строке 10090, которая выдаст на экран исправленную символьную строку А|. В строке 10280 введенная строка символов проверяется на максимум длины. Пока длина строки А$ остается равной L2, управление возвращается на строку 10130 и не выходит из цикла. Строки 10290—10350 содержат фильтр. Они проверяют, соот¬ ветствует ли введенный символ установленным критериям. Если это условие выполняется, то управление перейдет строке 10360, где В$ будет сцеплена с А$. Но если ни один из тестов не пройден успешно, то строка 10350 вернет управление строке 10130, и на¬ 141
чнется ввод в строку В$ следующего символа. После сцепления А$ и В$ управление будет передано строке 10090, которая выведет на экран обновленную строку А$. СОПОСТАВЛЕНИЕ МЕТОДОВ ВВОДА ДАННЫХ Какой из способов ввода данных предпочтительнее — исполь¬ зующий оператор INPUT, LINE INPUT или INKEY$? Ответ на этот вопрос зависит от особенностей конкретной программы. INPUT удобен в программах с ограниченными требованиями к вводу, но неудобен в серьезных программах. Основной его недо¬ статок заключается в том, что при нажатии клавиши «Ввод» может разрушиться кадр вывода. Кроме того, этот оператор не способен воспринимать некоторые символы, например запятую. В большинстве серьезных программ лучше применять оператор LINE INPUT. С помощью оператора INKEY$ можно воспринимать сигнал о том, что была нажата отдельная клавиша. Он позволяет воспринимать и последовательность таких сигналов. В первом случае он удобен для выдачи пользователю вопросов, требую¬ щих подтверждения. Например, после ввода нескольких показа¬ телей пользователю можно задать такой вопрос: Желаете что-либо изменить? (д/н) Для указания своего решения пользователь нажмет клавишу «д» или «н». В таких случаях ввод не надо завершать нажатием клавиши «Ввод». Но в большинстве случаев посимвольный ввод неудобен, поскольку пользователю надо видеть введенные им символы и иметь возможность их исправить или подтвердить нажатием на клавишу «Ввод». В описанной выше форме «люкс» оператор INKEY$ состав¬ ляет альтернативу операторам INPUT и LINE INPUT. Он может выборочно отслеживать нажатие на любую клавишу, отфильтро¬ вывать нежелательные данные и предотвращать чрезмерный рост входной последовательности символов. Короче говоря, он обеспе¬ чивает полную управляемость процесса ввода данных и дает га¬ рантию, что изображение на экране не будет разрушено. Если для вас это важно, то используйте оператор INKEY| вместо операто¬ ров INPUT и LINE INPUT. ПРИМЕНЯЙТЕ В ОПЕРАТОРАХ ВВОДА ТОЛЬКО СТРОКОВЫЕ ПЕРЕМЕННЫЕ В операторах ввода следует пользоваться только строковыми переменными. Строковые переменные могут содержать любые сим¬ волы, и ваш компьютер не станет «сходить с ума», если пользова¬ тель введет цифру, букву, любой другой символ или даже нажмет на клавишу «ввод», не набрав никаких данных. Но при вводе дей¬ 142
ствительной или целочисленной переменной оператор INPUT будет «вести себя более разборчиво». Если, например, в программе бу¬ дет выполняться такой оператор: 10 INPUT А а пользователь наберет на клавиатуре фразу «Шел дождь и два студента» и нажмет клавишу «Ввод», то ПК выдаст на экран сооб¬ щение об ошибке и знак вопроса. Попытку ввести с помощью оператора INPUT целочисленную переменную можно сравнить с игрой в рулетку: одни числа выигры¬ вают, а другие — проигрывают. Можно вводить только целые чис¬ ла, лежащие между —32768 и 32767. Наберите любое число, вы¬ ходящее за эти пределы, и программа «пойдет вразнос». Итак, значения, которые вы вводите с клавиатуры, присваивай¬ те только строковым переменным. Если вам надо ввести число, то преобразуйте введенные строки в эквивалентные числа с помощью оператора VAL. Иными словами, вводите числа с помощью опера¬ торов, подобных приведенным ниже: 10 INPUT А$ , 20 A = VAL (А$) ПРОЦЕСС ВВОДА Хорошо спроектированная процедура ввода данных не должна ограничиваться лишь приемом вводимых пользователем символов и их преобразованием в переменные, хранящиеся в памяти компью¬ тера. Этого недостаточно, хотя и встречаются процедуры ввода, ко¬ торые ничего другого не делают. Хорошая процедура ввода долж¬ на: • Выдавать пользователю подсказку, напоминающую, что именно ему следует вводить. • Принимать с клавиатуры вводимые пользователем показате¬ ли. • Проверять вводимые данные. • Давать пользователю возможность просмотреть и отредакти¬ ровать введенные данные. Неудачные процедуры ввода либо опускают некоторые из ука¬ занных действий, либо выполняют их плохо. Только при выполне¬ нии всех перечисленных работ можно получить полноценную процедуру ввода данных. Каждая из перечисленных функций налагает определенные тре¬ бования на проектирование ввода, и каждую из них можно реали¬ зовать неверно. Далее каждой функции будет посвящен отдель¬ ный параграф. В примерах будет использоваться оператор LINE INPUT — в основном для того, чтобы не загромождать програм¬ мный текст. Как только что было показано, иногда лучше вос¬ пользоваться моделью «люкс» оператора INKEY$. 143
ПОДСКАЗКИ Подсказки сообщают пользователю, что ему надо вводить. Подсказка должна выполнять следующие функции : • Сообщать пользователю, данные какого типа следует вво¬ дить. Подсказка должна быть одновременно информатив¬ ной и краткой, причем информативность важнее краткости. Приводимая ниже подсказка удовлетворяет обоим требова¬ ниям: Сообщите ваш месячный оклад: руб. __ а вторая подсказка кратка, но недостаточно информативна: Сообщите величину: Величину чего? Неясно!.. Могут запрашиваться рубли, лит¬ ры, килограммы и вообще любая величина, которую можно измерить числом. • Сообщать формат вводимых данных, если их надо представ¬ лять в каком-то специальном формате. Например, даты, время и номера телефонов обычно задаются в некотором осо¬ бом формате, который следует указать в подсказке. Наберите дату своего рождения: день/месяц/год, например 15/4/54: Теперь пользователь знает, "что ему следует ввести день, месяц и год своего рождения, разделяя их косыми чертами. Не получив подсказки, пользователь мог бы вводить дату различными способами, например как 15, 4, 54; 15—4—54; 15041954 и т. п. • Привлекать внимание пользователя. Подсказка является запросом, требующим ответа. Но если пользователь не видит подсказку или не понимает, что от него ожидают, то ответа на запрос может и не последовать. Поэтому подсказка долж¬ на бросаться в глаза. Мигающий курсор привлекает внима¬ ние и притягивает взгляд к подсказке. По возможности вклю¬ чайте в подсказку мигающий курсор. Кроме того, подсказку полезно выдавать в режиме инверсии или повышенной ярко¬ сти, благодаря которому она будет выделяться на экране. Для дополнительного выделения текст подсказки можно за¬ писывать большими буквами. Вспомните о принципе последовательности. Подсказки, запра¬ шивающие однотипные данные, выдавайте одинаковым образом. Не запрашивайте однотипную информацию по-разному, тем более в одной программе. КАК ПРИНИМАТЬ ВВОДИМЫЕ ДАННЫЕ Во время приема данных на экран обычно выдается кадр ввода данных. Вводя данные, пользователь смотрит на этот кадр. Некото¬ рые кадры предназначены только для ввода (рис. 5.4). Другие 144
Рис. 5.4. Кадр, полностью посвященный вводу данных (никакая ин¬ формация в этом кадре не выводится) Рис. 5.5. Кадр с информацией в верхней части и строкой ввода данных в нижней 145
ОПРОСНЫЙ ЛИСТ СТУДЕНТА ПОЖАЛУЙСТА, ОТВЕТЬТЕ НА СЛЕДУЮЩИЕ ВОПРОСЫ-: 1. ФАМИЛИЯ, ИМЯ, ОТЧЕСТВО 2. СПЕЦИАЛЬНОСТЬ 3. КУРС (ПОСТАВЬТЕ ОДНУ ГАЛОЧКУ) 1 ■+■ й 2- й 3- й 4- й 5- .й 1 4. ЗРЕНИЕ (ПОСТАВЬТЕ ОДНУ ГАЛОЧКУ) нормальное нуждаетесь в очках 5. СКОЛЬКО ЧАСОВ В СУТКИ ВЫ СПИТЕ? 6. ПИТАНИЕ (поставьте одну галочку) нормальное много углеводов много белков Рис. 5.6. Анкета, соответствующая кадру ввода данных, изображенному на рис. 5.4 кадры могут, кроме того, со¬ держать информацию, прямо или косвенно связанную с вводимыми данными (рис. 5.5). Полноэкранный ввод дан¬ ных. Наверное, вам при¬ ходилось пользоваться про¬ граммами, у которых кадр ввода выглядит аналогично представленному на рис. 5.4. Этот j здр похож на бланк стандартного бумажного до¬ кумента (рис. 5.6). Такой кадр может быть спроек¬ тирован на основе бумажно¬ го бланка, и чем больше он похож на такой бланк, тем лучше. Перенос данных с бу¬ мажных бланков в компью¬ тер— одна из наиболее ти¬ пичных работ. При этом кур¬ сор вначале располагается в первом поле входных данных. Как только пользователь наберет соответствующий показатель и нажмет клавишу «Ввод», курсор переместится в следующее поле. И так пользователь вводит после¬ дующие показатели, пока не заполнит весь кадр. Подобная орга¬ низация ввода данных называется полноэкранным вводом. Полноэкранный ввод удобен в тех случаях, когда данные пере¬ носятся со стандартных бланков или других бумажных носителей, имеющих четкий формат, например с банковских чеков. Если кадр подобен копии бланка, то пользователю будет легче выполнить эту работу. Кроме того, полноэкранный ввод удобен, когда пользо¬ вателю надо вводить связанные между собой данные, например курсы акций1, и если при вводе очередного показателя ему может понадобиться просмотреть ранее введенные. Сохранение на экране ранее введенной информации уменьшает риск пропустить очеред¬ ной показатель или ввести его дважды. Давайте спроектируем простой кадр ввода данных, а затем составим текст программы, формирующей этот кадр и осуществ¬ ляющей полноэкранный ввод. В нашем примере такой кадр должен обеспечивать ввод трех показателей: фамилии, возраста и пола. Эти показатели будут присвоены соответственно переменным 1 При публикации биржевых курсов обычно сообщается цена акций на момент закрытия биржи (конец дня), а также максимальная и минимальная цена в течение дня и иногда те же сведения за предыдущий день. — Примеч. пер. 146
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22|23! 24 25 26 27 28 29 30131 32 33 34 35 36 37 38 39 40 1 2 3 4 ф а м и л и я 5 6 7 8 8 о 3 р а с т 9 10 11 12 П о л 13 14 15 16 17 18 19 Г~ 20 21 22 23 1 24 I L I L L L L L L I I L 1 L I р 1 Г 1 1 1 Рис. 5.7. Разметка кадра ввода данных с помощью матрицы проектирования 0 REM Подпрограмма, вводящая данные с помощью оператора LINE INPUT 1 REM SAVE”A:FIG5-6” , А 1300 REM--Очистить‘одну строку-- 1310 LOCATE V,H:REM переместить курсор в требуемую позицию 1320 PRINT SPACER (WIDEZ-+1 -Н) ;: REM стереть все до конца строки 1330 LOCATE V,H:REM вернуть курсор в требуемую позицию 1340 RETURN 3010 REM--Ввод данных с помощью оператора LINE INPUT-- 3020 GOSUB 1300.‘REM очистить строку и определить место для подсказки 3030 COLOR 0,7:REM инверсия 3040 PRINT Рф+”:”;:REM вывод подсказки 3050 COLOR 7,0:REM нормальное отображение 3060 LINE INPUT Аф 3070 RETURN Рис. 5.8. Подпрограмма, принимающая данные с помощью оператора LINE INPUT NAMES$, AGE и SEX$. Впрочем, наш учебный проект легко модифицировать так, чтобы он позволял формировать намного более сложные кадры ввода данных. Для простоты будем пока предполагать, что допустимы любые значения этих переменных. Очевидно, что это не так, но давайте временно опустим контроль вводимых данных. Начнем с разметки кадра на матрице проектирования. Резуль¬ тат этой работы изображен на рис. 5.7. На экране размещаются 147
0 REH Программа полноэкранного ввода 1 REH SAVE"А:FIG5—9",А 960 WIDEZ-60 990 GOTO 10000 1300 REH--Очистить одну строку-- 1310 LOCATE V,H:REH переместить курсор в требуемую позицию 1320 PRINT SPACER(WIDEZ+1-Н);:REH стереть все до конца строки 1330 LOCATE V,H:REM вернуть курсор в требуемую позицию 1340 RETURN 3010 REM--Ввод.данных с помощью оператора LINE INPUT-- 3020 GOSUB 1300:REH очистить строку и определить место для подсказки 3030 COLOR 0,7 : REM инверсия 3040 PRINT Р|REM вывод подсказки 3050 COLOR 7,0;REH нормальное отображение 3060 LINE INPUT А| 3070 RETURN 10000 REH--Программа полноэкранного ввода— 10010 REH-Инициализация экрана- 10020 CLS 10030 COLOR 0,7:REM инверсия 10040 LOCATE 4, 1 10050 PRINT"фамилия:" 10060 LOCATE 6 10070 PRINT"Bo3pacT;” 10060 LOCATE 12 10090 PRINT"Пол:" 10100 COLOR 7,0:REH нормальное отображение 10110 REH-Подсказки и прием сигналов клавиатуры- 10120 REM-фамйлия- 10130 V-4 10140 Н=1 10150 Рф="фамилия" 10160 GOSUB 3010 10170 NAHES|=A$ 10160 REH-Возраст- 10190 V=6 10200 Рф-"Возраст" 10210 GOSUB 3010 10220 AGE-VAL(Al) 10230 REM-Пол- 10240 Vz12 10250 Р$="ПОЛ” 10260 GOSUB 3010 10270 БЕХфлАф 10260 END Рис. 5.9. Программа полноэкранного ввода данных соответствует проекту кадра ввода, изображенному на рис. 5.7 три подсказки, они располагаются в строках 4, 8 и 12. Подсказки будут выводиться, начиная с первого столбца. Целесообразность составления подпрограммы приема данных примите пока на веру. Рис. 5.8 содержит распечатку такой программы. В ней исполь¬ зуется подпрограмма стирания строки, описанная в гл. 4, хотя перемещать курсор и стирать строку можно было бы и без ее помо¬ щи. Подпрограмма ввода данных имеет три аргумента: V,"H и Р$. V и Н обозначают соответственно номер строки и столбца, в кото¬ рых будет выведена подсказка, а строка содержит текст под¬ сказки. После того как будут заданы эти аргументы и вызвана 148
подпрограмма, в указанном месте экрана в режиме инверсии будет выведена подсказка, а данные будут приняты с помощью оператора LINE INPUT и присвоены переменной А$. Подпрограмма работает следующим образом: строка 3020 сти¬ рает строку экрана, в которую будет выведена подсказка, и переме¬ щает курсор на нужное место. Строка 3030 включает режим ин¬ версии изображения. Строка 3040 выводит текст подсказки, при¬ соединяя к ней двоеточие. Строка 3050 отменяет инверсию. Строка 3060 с помощью оператора LINE INPUT принимает вве¬ денный показатель и присваивает его строке А|. Теперь составим текст, порождающий кадр ввода данных. Поскольку к началу ввода все подсказки должны уже присутст¬ вовать на экране, их придется выводить дважды. Сперва очистим весь экран, а затем выведем все подсказки. Потом вызовем под¬ программу выдачи подсказки и приема элемента данных, настроив ее на первый показатель. Далее то же самое сделаем со вторым и третьим показателями. Можно было бы изменить подпрограмму ввода и не выводить одни и те же подсказки дважды, но в других ситуациях будет удобнее, чтобы при вводе данных подсказки выдавались. На рис. 5.9 изображен программный текст, формирующий кадр ввода данных и принимающий эти данные. Подпрограмма ввода показателей расположена в строках 3000—3070. Строка 10020 очи¬ щает экран, строка 10030 включает режим инверсии изобра¬ жения, строка 10040 перемещает курсор, а строка 10050 выводит первую подсказку. Строки 10060 и 10070 соответственно переме¬ щают курсор и выводят вторую подсказку, а строки 10080 и 10090 делают то же самое с третьей подсказкой. Строка 10100 восстанавливает режим нормального отображения. Эти строки формируют кадр ввода данных. Строки 10130, 10140 и 10150 определяют строку и столбец, в которых будет выведена первая подсказка и ее текст (V, Н и Р$). Строка 10160 вызывает подпрограмму ввода показателя. В строке 10170 введенное значение будет присвоено переменной NAMESJL В строках 10180—10220 то же самое будет сделано с переменной AGE, а в строках 10230—10270—с переменной SEXJ. Ввод данных в одной строке. Программировать ввод данных в однсщ строке экрана значительно проще. Но не думайте, что такой организацией ввода пользуются только ради легкости кодирова¬ ния: она имеет несомненные преимущества в тех случаях, когда информация, представленная в другой части кадра, нужна поль¬ зователю при вводе. Например, кадр вывода может содержать спи¬ сок фамилий, каталог запчастей и другие сведения, от которых мо¬ жет зависеть решение пользователя. Написать программу ввода данных в одной строке довольно легко, особенно если воспользоваться подпрограммой ввода дан- 149
<b REM Программа ввода в Ъдну строку 1 REM SAVE"A:FIG5-10" ,А 960 WIDE’/. = 60 990 GOTO 10000 1300 REM--Очистить одну строку-- 1310 LOCATE V, H:REM переместить курсор в требуемую йозицию 1320 PRINT SPACE! (WIDEX<• 1-Н)REM стереть все до конца строки 1330 LOCATE V,H:REM вернуть курсор в требуемую позицию 1340 RETURN 3010 REM--Ввод данных с помощью оператора LINE INPUT— 3020 GOSUB 1300:REM очистить строку и определить место для подсказки 3030 COLOR 0,7:REM инверсия 3040 PRINT P|+":";:REM вывод подсказки 3050 COLOR .7,0: REM нормальное отображение 3060 LINE INPUT А! 3070 RETURN 10000 REM--Программа ввода в одну строку-- 10010 CLS 10020 REM-фамилия- 10030 Vz22 10040 Н=1 10050 P$z"фамилия" 10060 GOSUB 3010 10070 NAMES$=А! 10060 REM-Возраст- 10090 V=6 10100 Р$ ="Возраст" 10110 GOSUB 3010 10120 AGE=VAL(A$) 10130 REM-ПОЛ- 10140 V=12 10150 Р$:"ПОЛ" 10160 GOSUB 3010 10170 SEX$=A$ 10160 END Рис. 5.10. Программа ввода данных в одной строке них, например, представленной на рис. 5.8. Теперь вам больше не придется принимать ценность этой подпрограммы на веру. На рис. 5.10 приведена распечатка подпрограммы, которая вводит те же три переменные — NAMES|, AGE и SEX$, что и описанная выше программа полноэкранного ввода. Но новая программа бу¬ дет выдавать подсказки (в строке 22 экрана) и принимать показа¬ тели поочередно. Основная часть программы состоит из строк 10000—10160. Строка 10010 очищает экран. Строки 10030—10050 присваивают значения аргументам V, Н и Р1 для приема первой перемен¬ ной. В строке 10070 переменной NAMES$ присваивается введен¬ ное в строку Аф значение. В строках 10080—10110 принимается показатель AGE, а в строках 10120—10150— показатель SEX|>. Метод сдвига изображения по экрану (метод ролика). Теперь мы переходим к методу ввода данных, который используется, по¬ жалуй, чаще всего. Постарайтесь вспомнить самую первую напи¬ санную вами программу, в которой вводились данные. Вероятно, 150
Рис. 5.11. Если очистить экран и принимать вводимые показатели, не управляя расположением подсказок, то каждая новая подсказка будет появляться в следующей строке экрана Рис. 5.12. Если первую подсказку выдать в нижней части экрана, а расположением последующих не управлять, то старые подсказки будут сдвигаться вверх по экрану, а каждая последующая будет выдаваться в нижней строке 151
ввод осуществлялся последовательностью операторов INPUT, ко¬ торая выглядела примерно так: 10 INPUT ’’Фамилия:”; NAMES$ 20 INPUT ’’Возврат:”; AGE 30 INPUT ”Пол:”; SEX$ Что происходит на экране, когда выполняется такая програм¬ ма? Ответ зависит в основном от того, где выводится первая под¬ сказка. Если в верхней части экрана, то последующие подсказки будут выдаваться одна под другой (рис. 5.11). Но если первая подсказка будет выведена в нижней части экрана, то при появле¬ нии каждой новой подсказки изображение, и в том числе ранее вы¬ веденные подсказки, будут сдвигаться («подматываться») вверх по экрану (рис. 5.12). Этот метод ввода данных очень прост, но при его применении либо сдвигается вниз то место экрана, к которому должно быть привлечено внимание пользователя, либо происходит нежелательный сдвиг текста по экрану. Грубо говоря, программа ввода данных становится неряшливой. По возможности, избегайте этого метода. КОНТРОЛЬ ДАННЫХ Данные при вводе, как правило, следует контролировать. Те¬ стом на ошибки называется программный текст, проверяющий вве¬ денные пользователем данные на соответствие некоторым прави¬ лам и определяющий, имеют ли эти данные смысл. Используе¬ мая нами в качестве примера простенькая программа вводит всего три показателя: «Фамилия», «Возраст» и «Пол». Мы не включали в эту программу контроль данных, но, несомненно, сде¬ лали бы это, если бы с помощью составляемой программы нам нужно было принимать верные данные. Вид контроля зави¬ сит от природы проверяемых данных. Так, например: • Фамилию мы проверяли бы на длину, чтобы удостовериться, что число символов находится в определенных пределах, ска- жем^их должно быть не менее 2 и не более 24. Возраст мы проверяли бы на попадание в интервал значений, например от 2 до 99 лет. • Пол мы проверяли бы на тождество', он должен быть равен либо «м», либо «ж». Если не проводить контроль, то совершаемые при вводе ошиб¬ ки попадут в базу данных и позднее вызовут неприятности. Чем раньше вы выявите ошибки, тем лучше, а лучше всего их выявлять непосредственно в момент ввода данных. Однако одного выявления ошибок недостаточно. Об обнаруженных ошибках следует сооб¬ щать пользователю; при этом ему надо предоставить все сведения, необходимые для их исправления. Это делается с помощью сооб¬ щений об ошибках. Итак, в данном параграфе мы рассмотрим два 152
вопроса: как выявлять ошибки и как о них сообщать пользовате¬ лю? Собственно говоря, к этому и сводится контроль данных. Выявление ошибок. Простейший вид проверки данных — тест на тождество. Например, в ответ на такую подсказку: Сообщите, пожалуйста, ваш пол (м или ж):_ можно ввести только «м» или «ж». Следующий фрагмент програм¬ много текста формирует подсказку и тестирует данные на тождест¬ во: 10 INPUT ’’Сообщите, пожалуйста, ваш пол (м или ж):”; SEX$ 20 IF SEX$ < > ”м” AND SEX$ < > ”ж” GOTO 10 Проверки на тождество выполняются нередко. Однако еще ча¬ ще приходится определять, попадает ли-введенная величина в за¬ данный интервал. Предположим, что в вашей программе ввода данных есть такой фрагмент: 10 INPUT ’’Возраст:”; А$ 20 AGE = VAL(A$) Подсказка запрашивает возраст. Чем-то взволнованный поль¬ зователь может нажать клавишу «Ввод», не набрав никакого чис¬ ла. В таком случае возвращаемое функцией VAL значение равно нулю. Нулевое значение будет присвоено переменной AGE и в том случае, если пользователь наберет букву или специальный символ. Если,напротив, пользователь нажмет клавиши больше раз, чем это необходимо, то в машину может быть введено слишком большое число. Например, возраст пользователя может быть набран как 222 вместо 22. Легко проверить, попадают ли вводимые значения показателей в установленный числовой интервал, и отбросить непопадающие. Разумеется, при этом следует установить верхний и нижний предел допустимых значений. Предположим, что допусти¬ мым будет считаться возраст от 2 до 99 лет. Добавим в программу строку с тестом на попадание в интервал: 30 IF AGE <2 OR AGE> 99 GOTO 10 Строка 30 проверяет, не оказывается ли значение переменной AGE меньше 2 или больше 99. Если это значение вышло за пределы допустимых значений, управление будет передано на строку 10, повторно запрашивающую ввод возраста. Если значение перемен¬ ной заключено в допустимых пределах, то выполнение процеду¬ ры завершается. В строках программы, осуществляющих тесты, постоянно упот¬ ребляются операции отношения =,<и> и логические операции OR, AND и NOT. Простые проверки, вроде только что продемонст¬ рированной, не требуют сложных выражений. Но иногда в тестах употребляются весьма запутанные выражения. Так, если множе¬ ство допустимых значений несвязно (скажем, возраст должен быть заключен в пределах 1—23, 43—63 или равен 99 годам), то логи¬ ческое выражение заметно разбухает: 153
30 IF NOT ((AGE>=1 AND AGE<=23) OR (AGE> =43 AND AGE< =63) OR AGE = 99) GOTO 10 Вывод: надо либо совершенно свободно владеть подобными операциями, либо специально готовиться к составлению сложных тестов. В дальнейшем предполагается, что вы хорошо понимаете используемую в программах логику и поэтому логические выра¬ жения приводятся без пояснений. Теперь изучим некоторые другие способы контроля данных. Только что мы рассмотрели простейший тест на попадание в интер¬ вал, а именно проверку того, что введенные данные заключаются между верхней и нижней численными границами. Но на попада¬ ние в интервал можно проверять не только числа. Любой символ, который можно отобразить на экране компьютера, имеет шифр в коде ASCII. Найдите в приложении В шифры символов %, &, 4 и Е. Эти шифры равны соответственно 37, 38, 52 и 69. В коде ASCII наи¬ большее значение имеет символ Е, а наименьшее — символ %. Компьютеру известно значение шифра каждого символа. Для получения этого значения можно воспользоваться функцией ASC. Например, для определения шифра символа % в коде ASCII на¬ берите следующую команду: PRINT ASC (”%”) Теперь наберите такую команду: PRINT ”Е”>”%” На экран будет выведено число—1, т. е. символ Е больше, чем символ %. Компьютер установил это, сравнив шифры этих симво¬ лов. Поскольку в коде ASCII шифр буквы Е (латинской) больше шифра символа %, выражение ”Е”>”%” истинно, а его ариф¬ метическая величина равна —1. Из приведенного примера легко заключить, что проверку на интервал можно производить не только над числами, но и над бук¬ вами и другими символами. Предположим, что мы желаем спроек¬ тировать программу ввода данных, принимающую латинские бук¬ вы в интервале от А до Е, которым в коде ASCII соответствуют шифры от 65 до 69. Эту работу выполнят такие строки: 10 INPUT ’’Буква:”; А$ 20 IF А$<”А” OR А$>”Е” GOTO 10 Рассмотрим интересный пример программы, позволяющей вво¬ дить буквы от А до Е и цифры от 1 до 4: 10 INPUT ’’Символ: А$ 20 IF NOT ((А$>=”А” AND A$<=”E”)OR (А$> =”1” AND A$<=”4”))GOTO 10 Этот тест демонстрирует, как важно свободно владеть логичес¬ кими выражениями языка BASIC. Тесты могут либо опознавать недопустимые данные, либо, на¬ против, опознавать допустимые данные. Например, в программе: 154
10 INPUT ’’Буква: ”; A$ 20 IF A$<”A” OR A$>”E” GOTO 10 осуществляется поиск недопустимых данных: символов вне интер¬ вала. Переписав строку 20, проверку можно преобразовать в поиск допустимых данных: 20 IF А$>”@” OR A$<”F” THEN GOTO... (продолжение) В тех случаях, когда при возникновении ошибок целесообразно передавать управление назад, лучше искать недопустимые данные. Если, как в строке 20 предыдущего примера, опознаются допусти¬ мые данные, то для обработки ошибок в программу придется вста¬ вить лишнюю строку. Такая версия программы иллюстрируется следующим текстом: 10 INPUT ’’Буква: А$ 20 IF А$> =”А” OR А$< =”Е” GOTO 40 30 GOTO 10 40 END Как известно, положительную проверку можно заменить на от¬ рицательную добавлением в начало выражения слова NOT. На¬ пример, условие IF NOT (А$>>”@” AND A$<”F”) эквивалент¬ но условию IF А$с”А” OR -А$>”Е”. Проверять на попадание в интервал значений можно и строки, состоящие из нескольких знаков. В языке BASIC такие строки сравниваются посимвольно: до первого несовпадения пары симво¬ лов или конца одной из строк. В последнем случае более короткая строка считается меньшей. Предположим, например, что нам надо спроектировать процедуру ввода фамилий, расположенных в ал¬ фавитном (лексикографическом) порядке между буквами А и Е. Для этого можно воспользоваться маленькой программой, с кото¬ рой мы только что экспериментировали. Запустите эту программу, а затем попробуйте ввести различные фамилии, в том числе начинающиеся с букв A, D и Е, и посмотрите, что получится. Кроме тестов на тождество и на интервал значений, часто используется также тест на длину. Благодаря этому тесту число введенных символов можно держать в определенных пределах, скажем между 2 и 24. Такую проверку проще всего осуществить с помощью функции LEN. 10 INPUT ’’Фамилия (2—24 буквы): А$ 20 IF LEN(A$)<2 OR LEN (A$)>24 GOTO 10 Эта программа позволяет ввести любую строку символов, длина которой заключается в указанных границах. Длина введенной строки определяется в строке 20 программы с помощью функции LEN. Если эта длина меньше 2 или превышает 24, то управле¬ ние возвращается на строку 10. Как видите, тест на длину выпол¬ няется аналогично тесту на интервал. Эти примеры иллюстрируют основные концепции, на которых основан контроль данных. Конечно, примеры несколько упрощены и не рисуют полной картины. Первое упрощение заключалось 155
0 REM Программа полноэкранного ввода с простыми проверками на ошибки Г REM SAVE"A:FIG5-13",А 980 WIDEZz80 990 GOTO 10000 1300 REM--Очистить одну строку-- 1310 LOCATE V,H:REM переместить курсор в требуемую позицию 1320 PRINT SPACE!(WIPEZ+1-Н)REM стереть все до конца строки 1330 LOCATE V, H:REM вернуть курсор в требуемую позицию 1340 RETURN 3010 REM-jВвод данных с помощью оператора LINE INPUT-- 3020 GOSUB 1300:REM очистить строку и определить место для подсказки 3030 COLOR 0,7:REM инверсия 3040 PRINT P$+":";:REM вывод подсказки 3050 COLOR 7,0:REM нормальное отображение 3050 LINE INPUT А| 3070 RETURN 10000 REM--Программа полноэкранного ввода-- 10010 REM-Инициализация экрана- 10020 CLS 10030 COLOR 0,7:REM инверсия 10040 LOCATE 4,1 10050 PRINT”фамилия:" 10060 LOCATE 8 10070 PRINT"Bo3pacT:" 10080 LOCATE 12 10090 PRINT”Пол:” 10100 COLOR 7,0:REM нормальное отображение 10110 REM-Подсказки и прием сигналов клавиатуры- 101 ?0 REM-фамилия- 10130 V-4 10140 Н=1 10150 Р$="фамилия" 10160 GOSUB 3010 10170 NAMES!=А| 10171 REM-Проверка на ошибки- 10172 IF LEN(NAMES$)>=2 AND LEN(NAMESф)<=24 GOTO 10180 10173 GOTO 10160 10180 REM-Возраст- 10190 V:6 10200 P|="Возраст" 10210 GOSUB 3010 10220 AGE=VAL(A|) 10221 REM-Проверка на ошибки- 10222 IF AGE>=2 AND AGE<x99 GOTO 10230 10223 GOTO 10210 10230 REM-Пол- 10240 V=12 10250 Р$="Пол" 10260 GOSUB 3010 10270 SEX|=A| 10271 REM-Проверка на ошибки- 10272 IF SEX!x"M” OR 5ЕХ$;"Ж" GOTO 10280 10273 GOTO 10260 10280 END Рис. 5.13. Программа полноэкранного ввода. В своей основе совпадает с программой, изображенной на рис. 5.9, но содержит простые про¬ верки на присутствие ошибок в использовании оператора INPUT, слабые стороны которого вам известны, а также в возврате управления (при ошибке) на повтор¬ ную выдачу подсказки, сдвигающей изображение. Все это можно сделать гораздо изящнее, если воспользоваться описанной в дан¬ ной главе подпрограммой, содержащей оператор LINE INPUT: эта 156
подпрограмма выдает подсказку в фиксированной позиции экрана, предотвращая тем самым сдвиг изображения. Другое упрощение заключалось в том, что при проверках мы неявно предполагали допустимыми только прописные или только строчные буквы. Поскольку входные данные могут вклю¬ чать и те и другие буквы (иногда даже в одном элементе данных), контроль должен правильно на них реагировать. Как можно уви¬ деть в приложении В, в коде ASCII большие и малые буквы имеют различные шифры. ПК также отличает их друг от друга. Следо¬ вательно, если вы хотите, чтобы проверку проходили и те и другие буквы, то это следует предусмотреть в тестах. Если вы, напротив, желаете, чтобы контроль пропускал только прописные (строчные) буквы, то позаботьтесь о том, чтобы пользователь это понимал. Ни¬ что так не выводит его из себя, как прекращение работы про¬ граммы из-за того, что в ответ на вопрос «Желаете продолжить работу? (д/н)» было набрано «Д» вместо «д». На рис. 5.13 изображена новая версия программы полноэкран¬ ного ввода, которая ранее приводилась на рис. 5.9. Эта версия содержит несколько дополнительных строк, обеспечивающих конт¬ роль входных данных. Строка 10172 проверяет длину переменной NAMES|, строка 10222 проверяет переменную AGE на интервал значений, а строка 10272 проверяет переменную SEX| на тождество. Эти тесты совер¬ шенно очевидны: если данные их не проходят, то управление возв¬ ращается на формирование подсказки в той же позиции экрана. Следовательно, подсказки не будут сдвигать изображение. Сообщения об ошибках. Для того чтобы оставаться в добрых отношениях с пользователем, недостаточно только обнаруживать ошибки. Пользователь способен оценить контроль входных дан¬ ных, спасающий его от заполнения базы данных всяким мусором. Но он не будет его ценить, если в ответ на неверные данные вы¬ дается только повторная подсказка. Почти каждому, кто работал с компьютером, приходилось сталкиваться с ситуацией, когда он что-то вводил, а машина этого не принимала и все повторяла одну и ту же подсказку. Иногда компьютер выдает таинственное сообщение типа «Недозволенные данные» или «SYS.ERR 401», которое вызывает у пользователя недовольство. В такой ситуации пользователь нуждается в хорошем сообще¬ нии об ошибке. Поэтому каждый раз, как пользователь вводит неверные данные, выдайте перед повторением подсказки сообще¬ ние об ошибке. Это сообщение должно: • Привлекать внимание пользователя. Пусть компьютер даст звуковой сигнал, а сообщение мигает. • Указывать, в чем заключается ошибка. Сообщите пользова¬ телю, что неверно в его данных. • Сообщать пользователю, как выйти из создавшейся ситуа¬ ции. 157
Кроме того, сообщение должно располагаться рядом с подсказ¬ кой, чтобы пользователь мог связать сообщение с введенными им данными. На некоторое время сосредоточим свое внимание на техничес¬ ких аспектах выдачи сообщений об ошибках: составим подпро¬ грамму, которая подает звуковой сигнал и выводит мигающее сообщение об ошибке в заданной позиции экрана. Затем мы под¬ робнее обсудим, как составлять сообщения об ошибках. На рис. 5.14 приведена подпрограмма вывода сообщения об ошибке на экран. Эта подпрограмма расположена в строках с номерами 3200—3280. Она требует, чтобы в программу была вклю¬ чена подпрограмма стирания строки экрана и подпрограмма задержки на заданное время (см. гл. 4). Аргументами подпрограм¬ мы являются переменные V, Н и ERRORS^ — соответственно но¬ мер строки и столбца экрана, где будет выведено сообщение об ошибке, и текст сообщения. Подпрограмма сотрет все, что нахо¬ дилось в строке V, начиная со столбца Н и до правой границы экрана, так что сообщение об ошибке может занимать все доступное ему место. REM Подпрограмма сообщений об ошибках 1 REM SAVE”А:FIG5- 14. BAS” , А 1300 REM--Очистить одну строку-- 1310 LOCATE V,H:REM переместить курсор в требуемую позицию 1320 PRINT SPACES(WIDEZ+1-H)REM стереть все до конца строки 1330 LOCATE V, H:REM вернуть курсор в требуемую позицию 1340 RETURN 3200 REM--Сообщение об ошибке-- 3210 GOSUE 1300-.REM стереть строку 3220 COLOR 23,0:REM режим мигания 3230 PRINT ERRORS|:REM вывод сообщения об ошибке 3240 ВЕЕР 3250 COLOR 7,0: REM нормальное отображение 3260 TX15:GOSUB 4100:REM задержка на 5 секунд 3270 GOSUB 1300-.REM стираем сообщение 3260 RETURN 4100 REM--Задержка на ТХ секунд-- 4110 FOR А=1 ТО ТХ*967 4120 NEXT 4130 RETURN Рис. 5.14. Подпрограмма формирования в указанной позиции экра¬ на мигающего сообщения об ошибке (строки 3200—3280) Подпрограмма работает следующим образом. Строка 3210 очи¬ щает строку экрана, строка 3220 включает режим мигающего отображения, строка 3230 выводит сообщение об ошибке, строка 3240 выдает на динамик звуковой сигнал, строка 3250 восста¬ навливает режим нормального отображения, а строка 3260 вызы¬ вает пятисекундную задержку. Наконец, строка 3270 стирает сооб¬ щение об ошибке. С помощью этой подпрограммы можно вывести мигающее сооб¬ щение в любой позиции экрана. С ее помощью можно привлекать 158
внимание и к другим сообщениям. Однако не следует забывать, что пока выполняется эта подпрограмма, программа ожидает ее окончания. Работу подпрограммы вывода сообщения об ошибке можно продемонстрировать, если запустить программу, изображенную на рис. 5.14, поместив в нее предварительно такие строки: 990 GOTO 10000 10000 INPUT ”V: V 10010 INPUT ”H: H 10020 INPUT ’’Errors^: ”;ERRORS$ 10030 GOSUB 3200 10040 GOTO 1000 Теперь, когда вы увидели, как работает эта подпрограмма, настало время включить ее в изображенную на рис. 5.13 програм¬ му ввода. данных, чтобы в ответ на неверные входные данные появлялись сообщения об ошибках. На рис. 5.15 изображена эта программа со следующими изменениями: • Добавлены две подпрограммы: подпрограмма сообщения об ошибке (строки 3200—3280) и подпрограмма задержки на заданное время (строки 4100—4130). • Добавлены строки 10173, 10174, 10223, 10224, 10273 и 10274, задающие текст сообщений об ошибках и вызываю¬ щие подпрограмму вывода сообщений. Рассматриваемая программа обеспечивает полноэкранный ввод данных. Если пользователь ввел неверное значение показателя, то на месте соответствующей подсказки примерно на пять секунд выводится сообщение об ошибке, а затем вновь появляется под¬ сказка, позволяющая ввести данные повторно. Посмотрим, как работает эта программа. Для этого проследим, что происходит при вводе значения первого показателя в перемен¬ ную NAMES|. Основная часть текста программы уже анализиро¬ валась, так что обсудим лишь формирование сообщений об ошиб¬ ках. Строка 10172 контролирует введенное значение. Если данные оказались непригодными, то управление передается на строку 10173, где в строковую переменную ERRORS^ помещается текст сообщения об ошибке. Затем выполняется строка 10174, вызываю¬ щая подпрограмму вывода сообщения об ошибке. Позиция, в которую будет выведено сообщение, задается переменными V и Н. Эти аргументы используются также в подпрограмме ввода, где они задают позицию подсказки. Значения им были присвоены в строках 10130 и 10140, и далее они не переопределялись, следовательно, сообщение об ошибке будет выведено в той же позиции,’где располагалась подсказка на ввод. По возвращении из подпрограммы вывода сообщений управление переходит строке 10175' которая в свою очередь возвращает его строке 10160, где повторно вызывается подпрограмма вывода подсказки и вво¬ да показателя. 159
Описываемый процесс состоит из многих шагов, но в нем нет ничего сложного. С помощью приведенных выше процедур доволь¬ но просто встроить сообщения об ошибках в ваши собственные программы. Теперь вы знаете, как выводить сообщения, но вам следует знать, что в этих сообщениях говорить. Избегайте безликих неинформативных формулировок типа «ОШИБКА В ДАННЫХ». Как правильно составить сообщение об ошибке? Этот вопрос совсем прост, не правда ли? Пожалуй, и ответ столь же прост, 0 REM Программа полноэкранного ввода с подпрограммой сообщений об ошибках 1 REM SAVE”A:FIG5-15", А 960 WIDEZ=80 990 GOTO 10000 1*00 1310 1 320 1330 1340 3010 3020 3030 3040 3050 3060 3070 3200 3210 3220 3230 3240 3250 3260 3270 3200 4100 4110 4120 4130 10000 10010 10020 10030 10040 1005.0 10060 10070 10000 10090 10100 10110 10120 10130 10140 10150 10160 10170 10171 10172 10173 10174 10175 10100 REM--Очистить одну строку-- LOCATE V, H:REM переместить курсор в требуемую позицию PRINT SPACE!(WIDEZ+1-Н);:REM стереть все до конца строки LOCATE V,H:REM вернуть курсор в требуемую позицию RETURN REM--Ввод данных с помощью оператора LINE INPUT-- GOSUB COLOR PRINT COLOR LINE INPUT A! RETURN REM--Сообщение GOSUB COLOR PRINT BEEP COLOR TX=5:GOSUB 4100:REM задержка на 5 секунд GOSUB 1300:REM стираем сообщение RETURN REM--Задержка на TX секунд-- FOR А-- 1 ТО ТХ*987 NEXT RETURN REM--Программа полноэкранного ввода-- REM-Инициализация кадра- CLS COLOR 0,7:REM инверсия LOCATE 4, 1 PRINT"фамилия:" LOCATE 6 PRINT"BO3pacT: " LOCATE 12 PRINT"non:" COLOR 7,0:REM нормальное отображение REM-Подсказки и прием сигналов клавиатуры- REM-фамилия- V=4 Н= 1 р! ="фамилия" GOSUB 3010 names!=а! REM-Проверка на ошибки- IF LEN(NAMES!)>-2 AND LEN(NAMES!)<=24 GOTO 10160 ERRORS!;"Фамилия должна состоять из 2-24 символов1 GOSUB 3200 GOTO 10160 REM-Возраст- 1300:REM очистить строку и определить место для подсказки 0,7:REM инверсия Р!+":";:REM вывод подсказки 7,0:REM нормальное отображение об ошибке-- стереть строку режим мигания 1300'. REH 23,0:REM ERRORS^:REM вывод сообщения об ошибке 7,0:REM нормальное отображение 160
1>190 V=d 10200 Рф="Возраст" 10210 GOSUB 3010 10220 AGE-VAL(A$) 10221 REM-Проверка на ошибки- 10222 IF AGE>=2 AND AGE<=99 GOTO 10230 10223 ERRORS!="Допустим возраст от 2 до 99 лет" 10224 GOSUB 3200 10225 GOTO 10210 10230 REM-ПОЛ- 10240 V=12 10250 Рф="Пол" 10260 GOSUB 3010 10270 SEX$=A| 10271 REM-Проверка на ошибки- 10272 IF SEX!="M" OR SEX$=")lc" GOTO 10260 10273 ERRORS!="Введите, пожалуйста, 'м' или 'ж'" 10274 GOSUB 3200 10275 GOTO 10260 10280 END Рис. 5.15. Программа полноэкранного ввода. В программу, изображенную на рис. 5.13, добавлены сообщения об ошибках но он совсем не очевиден. Уравнение,Е = тс2 выглядит очень прос¬ то, но найти его смог только А. Эйнштейн. Конечно, составление сообщений об ошибках смешно сравнивать с разработкой теории относительности, однако здесь имеются свои тонкости. Хотелось бы, чтобы сообщения об ошибках были краткими, но информативными они должны быть обязательно. Не заставляйте пользователя гадать. Избегайте ироничных сообщений. Они наст¬ роят пользователя против вас и против вашей программы. Вообще, сообщения должны быть максимально корректными, насмешки по отношению к пользователю неуместны. Сообщение об ошибке должно привлечь внимание пользовате¬ ля, указать, в чем состоит ошибка, и, если это не очевидно, под¬ сказать, что ему делать. Чтобы привлечь внимание, обычно бывает достаточно мигания и звукового сигнала «бип», но если вы не уве¬ рены в их эффективности, то запрограммируйте выдачу какого- нибудь пугающего звука. Вам следует позаботиться об идентификации ошибок и подго¬ товить письменные сообщения о том, что с ними делать. Все сооб¬ щения, содержащиеся в нашем примере, указывают, в чем состоит ошибка. • Проверка фамилии: фамилия должна состоять из 2—24 сим¬ волов. • Проверка возраста: возраст должен быть заключен между 2 и 99 годами. • Проверка пола: введите, пожалуйста, либо «м», либо «ж». Первыедва сообщения идентифицируют ошибку, но не говорят, что с ней делать, поскольку это очевидно. Третье указывает, что следует делать, а ошибку определяет неявно. В программах ввода 6 Зак. 1488 161
данных, как правило, не надо объяснять, что делать в случае ошиб¬ ки, так как пользователь и так занимается вводом данных, а ошибочные показатели следует вводить повторно. Однако бывают случаи, когда необходимо объяснить, как исправить ошибку. Ситуации, требующие таких пояснений, часто встречаются при вводе управляющих данных, когда под неумелым управлением пользователя программа приходит в такое состояние, для выхода из которого надо выполнить нетривиальные действия. Сообщения об ошибках — своего рода литературный жанр, и они много говорят об авторе. Составленные программистом сообщения об ошибках осве¬ щают склад его мышления. И эти сообщения в чем-то подобны его почерку, подвергнутому психологическому анализу. Если, встретившись с ошибкой, ваша программа выдает информативное сообщение, то ее можно сравнить с ровным, округлым почерком. Если сообщения об ошибках непонятны или оскорбительны, то их можно уподобить почерку неорганизованного человека, пишу¬ щего мелкими, разорванными, несвязанными буквами. ВЕРИФИКАЦИЯ Термин «верификация» означает подтверждение истинности. Верификация производится на различных этапах работы с компьютером. В частности, в программах ввода данные верифи¬ цируются во время просмотра пользователем набранной им инфор¬ мации. Ввод считается незавершенным, пока пользователь не подтвердит его истинность, и только с этого момента данные превращаются из потенциально введенных в действительно введенные. Потребность в верификации существует потому, что при вводе пользователи могут ошибиться или решить что-то изменить. В программах для микрокомпьютеров верификация чаще всего осуществляется тремя способами, называемыми подтверждением с помощью клавиши «Ввод», верификацией строки и верификацией страницы. Подтверждение с помощью клавиши «Ввод». Это простейший способ верификации. Для подтверждения набранных данных ис¬ пользуется клавиша «Ввод». Вы постоянно пользуетесь этим методом, хотя, наверное, об этом и не задумываетесь. Верификация с помощью клавиши «Ввод» встроена в операторы INPUT и LINE INPUT. Каждый раз, как выполняется один из этих операторов, пользователь должен вначале набрать входные данные, а затем нажать клавишу «Ввод». Пока он ее не нажмет, ввод остается незавершенным. Иными словами, клавиша «Ввод» подтверждает набранные на клавиатуре данные. Верификация с помощью клавиши «Ввод» позволяет пользо¬ вателю распознавать ошибки и исправлять введенные данные, но 162
только до того момента, пока он не нажмет эту клавишу. Тем не менее такая возможность желательна, и вам следует пользоваться этим способом подтверждения во всех ситуациях, когда пользо¬ ватель может захотеть изменить набранные данные, в том числе при вводе показателей или при выборе по меню варианта ра¬ боты программы. Подтверждение с помощью клавиши «Ввод» возможно и без использования операторов INPUT или LINE INPUT. Этот метод верификации может быть предусмотрен и в процедурах, исполь¬ зующих оператор INKEY$. Например, он был включен в описан¬ ную в данной главе процедуру INKEY$ «люкс». Но сам по себе оператор INKEY$ верификацию не производит: он сразу присваиваетсоответствующей переменной значение, введенное при нажатии на клавишу, и не оставляет пользователю возможности подтвердить правильность введенных данных. Поэтому «голый» оператор INKEY$ неудобен для ввода данных. Верификация строки. Верификация строки заключается в том, что пользователю предоставляется возможность вернуться и исправить введенный показатель. Для этого выдается примерно такая подсказка: Не желаете ли вы изменить введенные данные? (д/н) Если пользователь нажмет клавишу «д», то управление возвра¬ тится на подсказку, позволяющую ввести данные повторно. Если будет нажата клавиша «н», то введенные данные будут подтвер¬ ждены, и программа перейдет к следующему шагу работы. Для иллюстрации приведем программу, которая принимает один показатель и дает пользователю возможность подтвердить его правильность: 10 INPUT ’’Фамилия: NAMESf 20 PRINT ’’Согласны? (д/н)”; 30 A$=INKEY$:IF А$=” ” GOTO 30 40 PRINT 50 IF А£=”н” GOTO 10 60 IF А$=”д” THEN END 70 GOTO 30 Строка 10 принимает с клавиатуры показатель. Строка 20 вы¬ водит подсказку «Согласны? (д/н)». Затем строка 30 вводит один символ. Строка 50 проверяет, не введен ли символ «н», и, если этот символ введен, возвращает управление на строку 10, позволяя пользователю ввести данные повторно. Если введен символ «д», то программа завершает работу (строка 60). Наконец, если была нажата какая-нибудь другая клавиша, то строка 70 возвращает управление строке 30 для приема другого символа. Достоинство верификации строк заключается в том, что пользо¬ ватель может вносить в данные изменения и после того, как была нажата клавиша «Ввод». Но этот способ верификации удобен только в тех случаях, когда требуется подтверждение небольшого числа показателей: представьте, на что будет похожа ваша работа, 163 6*
если надо будет ввести, скажем, 20 показателей и подтвердить каждый из них по отдельности. Все это вам очень быстро надоест, а дело будет продвигаться очень медленно. Поэтому в тех случаях, когда требуется подтверждение многочисленных данных, лучше воспользоваться верификацией страниц. Верификация страниц. Верификация страниц отличается от верификации строк тем, что пользователь подтверждает правиль¬ ность сразу целого набора данных. Верификация страниц часто используется совместно с полноэкранным вводом данных. По завершении ввода данных в последнем свободном поле экрана появляется подсказка примерно такого вида: Желаете что-нибудь изменить? (д/н) Если все было введено правильно, то пользователь нажимает клавишу «н», и программа продолжает свою работу. В противном случае пользователь набирает «д», после чего на экране появля¬ ется другая подсказка, например: Укажите номер исправляемого показателя:— В ответ пользователь набирает номер показателя, и курсор перемещается в соответствующее поле входных данных, разрешая повторный ввод. После ввода исправленного показателя вновь появляется первая подсказка, позволяя продолжить исправление данных. Эта процедура повторяется до тех пор, пока введенная страница не удовлетворит пользователя полностью. Для того чтобы можно было пользоваться таким методом ве¬ рификации, наименования вводимых показателей должны быть пронумерованы: тогда пользователь сможет указать, что именно он желает изменить. Верификация страниц не обязательно требует полноэкранного ввода данных, но хорошо с ним сочетается. Если данные верифицируются без полноэкранного ввода, то перед подтверждением их следует выдать на экран. Как программировать верификацию страниц? Первым делом следует пронумеровать все подсказки. Затем надо запрограммиро¬ вать вывод подсказки «Желаете что-нибудь изменить? (д/н)», завершающую ввод данных, и вывод подсказки, позволяющей указать номер исправляемого показателя. Предположим, что пользователь введет «д» и укажет номер показателя, который он хочет изменить. Тогда начинает работу более сложная часть программы. Она должна повторно выдать подсказку на ввод соответствующего элемента данных и принять вводимые символы, осуществляя при этом их контроль и производя прочую обработку, выполнявшуюся при первоначальном вводе данных. Если программа ввода данных состоит из последовательно исполняемых процедур, то невозможно просто вернуть управле¬ ние на процедуру ввода показателя, который требуется изменить; в противном случае после выполнения этой процедуры программа запросит повторный ввод всех последующих показателей, т. е. дан¬ 164
ных, которые пользователь исправлять не собирался. Пусть, например, программа принимает три показателя, а пользователь желает изменить первый из них. Если вы просто передадите управление на процедуру ввода этого показателя, то пользо¬ вателю придется повторно ввести все три элемента данных, иначе он не сможет продолжить свою работу. Единственное решение этой задачи — преобразовать каждую из процедур ввода очередного показателя в отдельную подпро¬ грамму, которую можно выполнять независимо от остальных. Тог¬ да, если пользователь пожелает изменить показатель номер один, 1ЕМ Программа полноэкранного ввода с проверками на ошибки, сообщениями верификацией вводимых данных SH SAVE"A:FIG5-16" , А WIDE*/. = 60 GOTO 10000 J REH--Очистить одну строку-- 5 LOCATE V,H:REM переместить курсор в требуемую позицию J PRINT SPACE! (WlDE’/. + l -Н); : REH стереть все до конца строки J LOCATE V, H-.REH вернуть курсор в требуемую позицию 5 RETURN 1 REH--Ввод данных с помощью оператора LINE INPUT-- 1 GOSUB 1300:REH очистить строку и определить место для подсказки f COLOR 0,7:REM инверсия S PRINT РфREH вывод подсказки i COLOR 7,0:REH нормальное отображение I LINE INPUT A! I RETURN f REH--Сообщение об ошибке-- I GOSUB 1300:REH стереть строку I COLOR 23,0:REH режим мигания I PRINT ERRORS$:REH вывод сообщения об ошибке I ВЕЕР I COLOR 7,0:REM нормальное отображение 1 TX-5:GOSUB 4100:REH задержка на 5 секунд I GOSUB 1300:REH стираем сообщение ! RETURN > REH--Подсказка на верификацию-- I GOSUB 1300:REH стереть строку COLOR 0, 7:REM инверсия PRINT"He хотите ли что-нибудь изменить? (д/н):"; COLOR 7,0:REM нормальное отображение A$=INKE?|:IF А|=”” GOTO 3400 IF А|О"Д" AND А|о"Н" GOTO 3400 IF А|="н" THEN A=0:GOTO 3500:REM без изменений Рф="Укажите номер изменяемого показателя" GOSUB 3010:REM вызов подпрограммы ввода данных A=VAL(A$) IF А>=1 AND A< = N GOTO 3500 ERRORS!="Число должно находиться между 1 и"+STR|(N):РЕНхСООбщение об ошибке GOSUB 3200:REM вызов подпрограммы сообщений об ошибках GOTO 3430:REM пусть пользователь, укажет другой номер показателя RETURN REH--Задержка на ТХ секунд-- FOR А=1 ТО ТХ*967 NEXT RETURN 0 REH--Программа полноэкранного ввода-- 0 REH-Инициализация кадра- 0 CLS 0 COLOR 0,7:REM инверсия 0 LOCATE 4, 1 0 PRINT"1. фамилия:" 165
10060 LOCATE в 10070 PRINT"2. Возраст:* 10060 LOCATE 12 10090 PRJMT"3. Пол:" 10100 COLOR 7,0:REM нормальное отображение 10110 REM-Прием вводимых данных 10120 GOSUB 1024-0: REH фамилия 10130 GOSUB 10360:REM Возраст 10140 GOSUB 10470:REM Пол 10150 REM-Верификация- 10160 V:22:REM строка верификации 10170 1:REM столбец верификации 10160 N=3:REH число подсказок 10190 GOSUB 3350:REM обращение к подпрограмме верификации 10200 IF А=0 GOTO 10230:REM все введено правильно 102'0 ON A GQSUB 10240, 10360, 10470:REM исправляем Фамилию, возраст или пол 10220 GOTO 10160 10230 END:REM все введенные данные верифицированы 10240 REM-фамилия- 10250 V=4 10260 Н=1 10270 Рфг"1, фамилия" 10260 GOSUB 3010 10290 NAMES|еА| 10300 REM-Проверка на ошибки- 10310 IF LEN(HAMESS)>=2 AND LEN(NAMES*)<=24 GOTO 10350 10320 ERRORS!="фамилий должна состоять из 2-24 символов" 10330 GOSUB 3200 10340 GOTO 10280 10350 RETURN 10360 REM-Возраст- 10370 V=8 10380 Рф="2. Возраст" 10390 GOSUB 3010 10400 AGE=VAL(A!) 104,10 REM-Проверка на ошибки- 10420 IF AGE>-2 AND AGE<=99 GOTO 10460 10430 ERRORS!="Допустим возраст от 2 до 99 лет" 10440 GOSUB 3200 10450 GQTO 10390 10460 RETURN 10470 REM-Пол- 10480 Vx12 10490 P$-"3. Пол" 10500 GOSUB 3010 10510 sex!=a! 10520 REM-Проверка на ошибки- 10530 IF SEX!="M" OR SEX!-"*" GOTO 10570 10540 ERRORS*-"Введите, пожалуйста, 'м' или 'ж'" 10550 GOSUB 3200 10560 GOTO 10500 10570 RETURN P и с. 5.16. Программа полноэкранного ввода, основанная на рис. 5.15, но с до¬ бавлением верификации введенных данных программа сможет обратиться к соответствующей подпрограмме, не затрагивая введенных данных. Короче говоря, если вы решите верифицировать страницы, то вам понадобится реорганизовать свою программу. Эта реоргани¬ зация несложна, но может потребовать несколько иного взгляда на программу. Вскоре мы увидим, как следует преобразовывать программу, но вначале разработаем подпрограмму, выдающую подсказки на верификацию. 166
Подсказки на верификацию можно формировать как с по¬ мощью подпрограмм, так и непосредственно. Но если верификация осуществляется достаточно часто, то, безусловно, лучше будет воспользоваться подпрограммой. Впрочем, даже если вы склонны избегать таких подпрограмм, вам, несомненно, пригодится исполь¬ зуемая в них техника. Рис. 5.16 содержит пересмотренную версию программы полно¬ экранного ввода, изображенной на рис. 5.15. Новая версия обла¬ дает всеми возможностями предыдущей и, кроме того, преду¬ сматривает верификацию страниц. Анализ программы, изображенной на рис. 5.16, начнем с того, что рассмотрим, как работает подпрограмма верификации, содер¬ жащаяся в строках 3350—3500. Эта подпрограмма вызывает подпрограммы 1300, ЗОЮ и 3200, а подпрограмма 3200 в свою очередь вызывает подпрограмму 4100. Поэтому в программу необ¬ ходимо включить эти четыре подпрограммы. Аргументами под¬ программ выступают переменные V, Н и N. V обозначает номер строки, а Н — столбца, в которых должна быть выведена подсказ¬ ка верификации. N обозначает число показателей, которые, возможно, потребуется исправлять, т. е. число выданных на экран подсказок и введенных показателей. При вызове этой подпрограммы на экран первым делом выво¬ дится такая подсказка: «Не хотите ли что-нибудь изменить? (д/н)» Если пользователь наберет «н», то переменная А становится равной нулю, и управление возвращается вызывающей программе. Если пользователь нажмет клавишу «д», то на следующем шаге переменная А станет равной номеру показателя, который требуется ввести заново. Следовательно, переменная А несет в себе ин¬ формацию о том, следует ли исправлять верифицируемые дан¬ ные. Теперь, закончив предварительное обсуждение, рассмотрим ра¬ боту указанной подпрограммы. Строка 3360 стирает курсор и пе¬ ремещает его в нужную позицию. Строка 3370 устанавливает режим инверсии отображения. В этом режиме строка 3380 выводит первую подсказку верификации. Строка 3400 вводит один символ, а строка 3410 проверяет, допустим ли этот символ (он должен быть равен «д» или «н»), и, если допустим, возвращает управ¬ ление на строку 3400. В строке 3420 проверяется, не введен ли символ «н». Если введен, то переменной А присваивается значение нуль, а управ¬ ление передается на строку 3500, которая в свою очередь воз¬ вращает его вызвавшей программе, тем самым завершая работу подпрограммы. Если пользователь введет «д», то будут выполняться строки 3430—3490. Строка 3430 определяет значение переменной Р$, содержащей подсказку, которая будет выдана на экран, когда 167
строка 3440 вызовет подпрограмму ввода данных, начинающуюся в строке ЗОЮ. Строка 3450 преобразует в число переменную, возвращенную подпрограммой ввода данных, а строка 3460 про¬ верит это число на попадание в интервал значений. Если число не проходит проверку, то это означает, что пользователь неверно ввел номер изменяемого показателя. В таком случае строка 3470 определит текст сообщения об ошибке, который будет выдан под¬ программой, вызываемой в строке 3480. Затем строка 3490 возвра¬ тит управление на строку 3430, позволяя пользователю ввести другой номер показателя. Проанализировав подпрограмму верификации, рассмотрим, как будет работать вся программа. Программа ввода состоит из строк 10000—10570. В ней содержатся три подпрограммы ввода данных, начинающиеся в строках 10240, 10360 и 10470. Все они имеют одинаковую структуру, так что рассмотрим подробно только первую, начинающуюся в строке 10240. Эта подпрограмма прини¬ мает значение переменной NAMES$. Она состоит из строк 10240—10350. Ее текст будет для вас знаком, поскольку он почти идентичен тексту строк 10120—10175 (см. рис. 5.15), уже обсуж¬ давшемуся в данной главе. Кроме перенумерации» строк, в этот фрагмент программы были внесены два изменения: подсказке теперь предшествует номер, а в конец фрагмента добавлен опера¬ тор RETURN. Аналогичные изменения были внесены и в процеду¬ ры приема значений переменных AGE и SEX$. Рассмотрим текст, содержащийся в строках 10000—10230. Этот текст управляет работой программы. Строки 10000—10100 форми¬ руют кадр ввода данных. Эти строки идентичны соответствую¬ щим строкам программы, изображенной на рис. 5.15. Строка 10120 вызывает первую подпрограмму ввода данных, начинаю¬ щуюся в строке 10240. Строки 10130 и 10140 вызывают две другие подпрограммы ввода данных. Фрагмент программы, управляющей процессом верификации, начинается в строке 10150 и продолжается до конца управляю¬ щего модуля. Строки 10160—10180 задают аргументы подпро¬ граммы верификации. В результате в первом столбце строки 22 экрана появится подсказка верификации. Она позволит ввести номер показателя, который должен быть заключен между 1 и 3. Программа верификации вызывается в строке 10190. Если возвра¬ щаемое подпрограммой значение переменной А равно нулю, то ничего изменять не требуется и управление передается со строки 10200 на строку 10230, завершающую работу программы. Если значение переменной А, возвращаемое подпрограммой верификации, равно 1, 2 или 3, то строка 10210 вызовет соот¬ ветствующую подпрограмму ввода данных, после чего строка 10220 возвратит управление строке 10160; пользователь может снова проверить данные и, если надо, внести дальнейшие изме¬ нения. 168
Если вы не привыкли строить программы из блоков, то настоя¬ щая программа может показаться вам чересчур «закрученной». Даже если вы обладаете большим опытом, вам, возможно, все же будет трудно проследить ее логику. С другой стороны, она может показаться вам и совершенно прозрачной. Как бы вы ни оценивали эту программу, не пожалейте времени и проследите по настоящим пояснениям ее работу. Эта программа является хорошим примером того, насколько сокращается управ¬ ляющая часть программы, если ее строить из мощных подпро¬ грамм. Обратите внимание, что, хотя данная программа довольно велика, ее управляющая часть состоит из строк 10100—10230, т. е. всего из 14 строк, две из которых занимают примечания, а третью— оператор END. Иными словами, логика этой программы содержит¬ ся всего в 11 строках, выполняющих свою работу в основном с помощью подпрограмм. Рассматривая программу с этой точки зрения, вы видите, что она намного проще, чем была бы, если бы в ней не использовались подпрограммы. Если я вас еще не убедил, то подумайте, как бы вы написали программу, которая выполняет те же функции, но не содержит подпрограмм. Рис. 5.16 иллюстрирует основную структуру и логику верифика¬ ции страниц ранее введенных данных. Теми же методами можно пользоваться и в программах, обновляющих базу данных. Про¬ граммирование редактирования баз данных во многом подобно программированию верификации страниц. Основное различие между программами двух этих типов заключается в Сроках пересмотра и редактирования введенных данных. В программах верификации это делается через несколько секунд или минут после ввода. В программах редактирования баз данных та же работа выполняется через несколько дней, недель или месяцев.
Глава 6 УПРАВЛЕНИЕ РАБОТОЙ ПРОГРАММЫ • Большинство программ для ЭВМ нуждается в управлении. Программами для микроЭВМ чаще всего управляют с помощью меню, представляющих собой списки задач, которые может выпол¬ нить программа. Пользователь просматривает меню, находит нуж¬ ную ему функцию программы и нажимает на клавиатуре букву, цифру или функциональную клавишу, указывающую на выбран¬ ный им вариант, а компьютер послушно выполняет приказание. Меню очень популярны, но существуют и другие способы управле¬ ния, которые можно использовать вместо меню или в дополнение к ним. В данной главе описываются три самых распространенных метода управления работой ЭВМ: управление с помощью меню, простого выбора и вводимых пользователем команд. Любой способ управления предполагает ввод в ЭВМ управ¬ ляющей информации. При этом, как и в случае ввода любой другой информации, пользователь может совершать ошибки. По¬ этому в программе должен быть предусмотрен контроль данных (осуществляемый способами, рассмотренными в гл. 5). Если вы не знакомы с этими способами и не читали гл. 5, то вначале прочтите ее, а затем переходите к данной главе. В тексты программ, приведенных в настоящей главе, включены фрагменты, осущест¬ вляющие проверку данных на присутствие в них ошибок; подроб¬ но останавливаться на этих фрагментах мы не будем. Ввод данных и управление программой имеют много общего. В обоих случаях пользователь вводит данные, значения которых при¬ сваиваются некоторым переменным. И в том и в другом случае необходим контроль данных программой и их подтверждение поль¬ зователем. Но между вводом данных и управлением программой существует по меньшей мере одно существенное различие. Введен¬ ные показатели становятся частью базы данных программы и вли¬ яют на выводимую в кадрах вывода информацию. Управляющие данные определяют действия программы, например: будет ли она выдавать пользователю результаты анализа, станет ли обновлять файлы или завершит свою работу. Если представить программу в виде дорожной сети, соединяю¬ щей выполняемые этой программой функции, то управляющие дан¬ 170
ные будут указывать дорогу, по которой следует двигаться. Продолжая это сравнение, можно сказать, что обычные входные данные будут определять, кому, где и когда входить и выходить из машины. В значительной степени именно от способа управления зависит, насколько сложно будет изучать программу и работать с ней. При выборе метода управления приходится принимать ряд решений. На эти решения влияют главным образом три фактора: сложность освоения программы, удобство работы с ней и скорость работы программы. Выигрывая в одном, мы часто теряем в другом. Что бы ни думали некоторые преподаватели и авторы книг по программированию, простота в освоении программы всегда жела¬ тельна. Если человек научился чему-то трудным способом, его характер не становится от этого лучше — скорее наоборот. Но что делает один способ управления проще в освоении, чем другой? Од¬ нозначно на этот вопрос ответить нельзя, но одним из наиболее существенных факторов является объем сведений, которые необхо¬ димо запомнить пользователю. Поскольку в меню указываются все варианты работы программы, пользователь может не держать их в памяти, а просматривать меню по мере необходимости. Следо¬ вательно, такой метод управления сравнительно просто освоить. Если возможности программы не выдаются в виде меню, то поль¬ зователю приходится запоминать все режимы работы программы. Ясно, что такую программу изучать труднее, но не всегда этот ее недостаток оказывается решающим. Простота освоения программы зависит также от логичности структуры управления ею (или от отсутствия всякой логики). Логичную структуру управления можно сравнить с геометрически правильной паути¬ ной, нелогичную — с вороньим гнездом. Некоторые способы управления более удобны, чем другие. Удобство определяется не только выбранным методом управления, но и его реализацией. Ситуацию дополнительно осложняет то обстоятельство, что простота программы в освоении часто сопря¬ жена с трудностью в работе и наоборот. Например, выдача на экран многочисленных и подробных подсказок облегчает освоение программы, но когда пользователь эту программу освоит, те же подсказки будут замедлять его работу. Очень важна скорость работы программы; в некоторых слу¬ чаях она даже важнее, чем простота программы в освоении и работе. Способы управления различаются по их влиянию на быстродействие программы, но не всегда самый быстрый способ оказывается и самым лучшим. Разрабатывая структуру управления программой, часто прихо¬ дится принимать компромиссные решения, выбирая между просто¬ той освоения, удобством и скоростью работы. Как правило,, про¬ граммы с меню оказываются самыми простыми при освоении и самыми удобными в работе, но при этом довольно медленными. 171
На первый взгляд может показаться, что всегда приходится чем-то поступаться. Но это не так. В данной главе будет показано, как, комбинируя разные методы управления, объединить их достоинства. Для того чтобы вы смогли делать это про¬ фессионально, вам необходимо освоить все известные методы управления и уяснить сильные и слабые стороны каждого из них. В начале этой главы речь пойдет о принципах проектирования управления работой программы. Затем описываются наиболее рас¬ пространенные методы управления: меню, простой выбор и коман¬ ды. Хотя в главе рассказывается о трех способах управления, основное ударение делается на метод меню. Меню не является универсальным способом решения всех проблем, с которыми стал¬ кивается программист, но тот факт, что они становятся все более популярными и все шире используются в программах для микрокомпьютеров, не случаен. В последнем параграфе главы мы покажем, как, комбинируя меню и команды, можно сохранять все достоинства обоих методов управления. В главе приводится много примеров программных текстов и несколько полезных под¬ программ. ПРИНЦИПЫ ПРОЕКТИРОВАНИЯ УПРАВЛЕНИЯ ПРОГРАММОЙ При проектировании управления программой следует придер¬ живаться двух принципов: принципа простоты и принципа после¬ довательности. ПРИНЦИП ПРОСТОТЫ Рассмотрим еще раз аналогию между управлением программой и дорожной сетью. Различные дороги соответствуют связям между выполняемыми программой функциями, а перекрестки соответ¬ ствуют точкам, в которых пользователь управляет программой. Эту сеть часто называют структурой управления. Чем сложнее структура, тем сложнее освоить программу. Бывали ли вы в городах, улицы которых неудачно спроекти¬ рованы, а план устарел? В таких городах много тупиков, развет¬ вляющихся под неудобными углами улиц, объездов и нестан¬ дартных развязок. Если вы живете в таком городе, то рано или поздно перестаете все это замечать. Но приезжему, привыкшему к более простой и обычной структуре улиц, легко будет в нем заблудиться. Если вы переедете в такой город, то вам потре¬ буется некоторое время на то, чтобы в нем освоиться. Поначалу все будет сбивать вас с толку, но через определенное время и с по¬ мощью хорошего плана вы начнете ориентироваться в его улицах. 172
В конце концов вы найдете способы использовать их нестан¬ дартную структуру. Скажем, некоторые нелепые развязки, необыч¬ ные углы между улицами и т. п. дадут вам возможность быстро добираться из одного места в другое. После того как вы изучите дорожную систему города и привыкнете, к ней, она, возможно, даже начнет вам нравиться. Вы будете понимать, что она неудобна для приезжих, но вас и других старожилов она будет вполне устраивать. Быть может, это и не очевидно, но аналогия между дорожной сетью и структурой управления программой имеет глубокие корни. Простую структуру проще освоить и ею легче пользоваться, но она может оказаться неэффективной. Напротив, более сложная структура может допускать более быструю работу. Но на ее освое¬ ние вам придется затратить больше труда. При проектировании программ для микрокомпьютеров пред¬ почтение, как правило, отдается легкости освоения. Позднее, при обсуждении сетей меню, я приведу конкретные примеры того, как добиваться такой легкости. Сложность управления программой может зависеть и от того, какие названия вы даете различным элементам программы, т. е. от того, как вы владеете родным языком. Подбирайте простые, информативные названия. Это относится к названию самой программы, заголовкам кадров вывода и названиям процедур, ко¬ торые должны быть выполнены. Избегайте абстрактных, слож¬ ных и использующих технический жаргон наименований; приме¬ няйте вместо этого простые, конкретные, описательные термины. Чтобы лучше понять, о чем идет речь, представьте,что вы в первый раз работаете с некоторой программой. Какое меню вам было бы легче понять: изображенное на рис. 6.1 или на рис. 6.2? ПРИНЦИП ПОСЛЕДОВАТЕЛЬНОСТИ Принцип последовательности предполагает, что одинаковая работа выполняется одним и тем же способом. Любому пользователю будет легче осваивать программу, которая разраба¬ тывалась последовательно, поскольку в таком случае ему придется запоминать меньше различных сведений. Но как приложить этот общий принцип к проектированию программ? Ответ на этот вопрос легче всего понять на конкретном примере. Предположим, что вы учитесь работать с новой про¬ граммой, в которой используются меню. Пусть первое меню выгля¬ дит так, как изображено на рис. 6.2. Отметим некоторые его особенности. • Меню снабжено заголовком, содержащим слово «меню». • Представленные в меню варианты работы программы прону¬ мерованы. • Эти варианты расположены в центре экрана. • Текст вариантов состоит из пар: глагол — существительное. 173
ВАРИАНТЫ РАБОТЫ С ФАЙЛОМ 1. ИНИЦ. 2. АННУЛИРОВАТЬ •3. РЕД. 4. ВЫДАТЬ 5. ОТКЛЮЧИТЬСЯ ВАШ ВЫБОР?- Рис. 6.1. Меню с непонятными вариантами. Что бы этот кадр мог означать? Рис. 6.2. Меню, варианты которого представлены простыми пара¬ ми глагол-существительное. Такие тексты вариантов легко понять 174
• Подсказка требует, чтобы пользователь ввел номер выбран¬ ного им варианта. • За подсказкой следует мигающий курсор. • Последний из вариантов называется «ЗАВЕРШИТЬ РАБО¬ ТУ ПРОГРАММЫ». Теперь предположим, что вы выбрали по этому меню один из вариантов и программа выдала вам на дисплей кадр, изобра¬ женный на рис. 6.3. Похоже, что на нем изображено меню, но: • В заголовке нет слова «меню». • Строки текста выравнены по левому полю. • Варианты (если это варианты) не пронумерованы. • Тексты вариантов состоят из одних глаголов. • Нет ни подсказки, ни курсора. • Нет варианта «ЗАВЕРШИТЬ РАБОТУ ПРОГРАММЫ». Последний вариант назван «ПОКИНУТЬ». Понять, что это меню — нетрудно, но оно не похоже на преды¬ дущее. Получив такой кадр, пользователь должен разобраться, что изображено на экране. Он думает примерно так: «Полагаю, что это меню. Теперь проверим это предположение. Менюдолжны обладать свойствами А, В и С. Рассмотрим содержимое кадра. Нет, свойством А оно не обладает. Похоже, что оно облада¬ ет свойством В. Относительно свойства С я не уверен...». Рис. 6.3. Не всегда очевидно, что на экране действительно изоб¬ ражено меню. Например, в меню, изображенном на рисунке, нет заголовка и строки подсказки и неясно, как следует указывать выб¬ ранный вариант 175
Из этого видно, что незачем заставлять пользователя высту¬ пать в роли исследователя. Не затрудняйте его работу. Будьте последовательны. МЕНЮ Что такое меню? Я уже приводил общее определение меню, но для полноты и последовательности дадим этому термину более формальное определение. Меню состоит из списка вариантов работы программы и процедуры ввода данных, позволяющей поль¬ зователю выбрать один из этих вариантов. Это, конечно, минимум. Меню может содержать, и обычно содержит, не только эти два ком¬ понента. Фирмы-изготовители программного обеспечения при рекла¬ мировании своей продукции часто упоминают, что их программы дружественны пользователю и снабжены меню. Многие из про¬ грамм, публикуемых в книгах и журналах, также используют меню. Чем же меню хороши? В ответ на этот вопрос, пожалуй, лучше всего рассмотреть альтернативу меню, а именно пустой экран. В самом деле, многие программы, в особенности сложные, ничего другого пользователю и не предоставляют. Чтобы работать с такой программой, ему приходится извлекать список вариантов из собственной памяти. Слово «меню» — удачное название для рассматриваемого способа общения с программой. В большинстве ресторанов вам кладут меню на стол или вывешивают его при входе. В меню столовой очень легко разобраться. В китайском ресторане на то, чтобы прочесть меню, может уйти несколько часов. В изысканных (или претендующих на изысканность) ресторанах меню может быть не написано, о том, что сегодня готовится, вам расскажет модно одетый метрдотель. Но в какой бы форме меню ни было представ¬ лено, оно должно сообщать, что вы можете выбрать. В про¬ тивном случае вы сможете что-нибудь заказать, только если заранее знаете, какие блюда готовят в этом ресторане, или если кого-нибудь об этом спросите. Однако на персональной ЭВМ обычно не работают коллективно, и задавать. вопросы некому. Не всем нравятся меню. Многие квалифицированные пользо¬ ватели относятся к ним примерно с таким же чувством, с каким мастер спорта по бегу отнесся бы к тренировке совместно со школьной командой. Такие специалисты список вариантов зна¬ ют наизусть и не нуждаются в меню. Меню и связанная с ним задержка им неприятна: они хотят сразу же перейти к делу. Некоторые программы содержат большое число меню, и что¬ бы начать работу с нужной частью программы, пользователю приходится проходить весь путь, от меню к меню. Специа¬ листу это может быть скучно, и к тому же на это тра¬ 176
тится много времени. Следовательно, в меню есть свои хорошие и плохие стороны. Меню стоит использовать не в любой программе. Однако в большинстве программ они уместны. Меню можно проектировать различными способами. Мы обсу¬ дим два типа меню: занимающие весь экран и занимающие часть экрана. Меню, занимающие весь экран, изображены на рис. 6.1, 6.2 и 6.3. Такой вид часто имеют главные меню программы. Когда они выдаются на экран, ничего другого на него не выводится. Меню, занимающие часть экрана, обычно выводятся на экран дисплея одновременно с другой информацией, рас¬ положенной в оставшейся части кадра. Подобные меню часто применяются для управления выводом информации на экран: например, с их помощью можно изменять масштаб или другие графические характеристики выводимого на экран изображения. Оба типа меню полезны, но обычно они используются в раз¬ ных ситуациях. МЕНЮ, ЗАНИМАЮЩИЕ ВЕСЬ ЭКРАН На рис. 6.2 изображено типичное полноэкранное меню. Такие меню имеют следующие части. • Заголовок меню. Выдается по центру верхней части экрана в режиме инверсии. Он целиком записан прописными бук¬ вами. Содержит слово «меню». • Выбираемые варианты. Данное меню содержит пять вариан¬ тов, пронумерованных числами 1—5. • Строка подсказки. Строка, в которой пользователь вводит номер варианта, выбранного им по меню. Как ранее отмечалось, меню может содержать не только эти три компонента. Вскоре мы обсудим, что еще может быть включено в меню. Но вначале давайте разберемся, почему эти три главных компонента меню не столь просты, как это может по¬ казаться. Заголовок. Рекомендую вам располагать заголовок по центру верхней части экрана или на несколько строк ниже верхнего края — если так меню будет выглядеть лучше. Советую выводить заголовок только большими буквами. Режим инверсии не обязате¬ лен, это вопрос стиля. В данной книге мы придерживаемся соглашения, согласно которому заголовки, «шапки» и большинст¬ во подсказок выводятся большими буквами в режиме инверсии. То, что принято именно такое соглашение, не очень существенно: важно иметь какую-нибудь договоренность, позволяющую поль¬ зователю отличать заголовки, «шапки» и подсказки от другой ин¬ формации, расположенной на экране. Варианты. Рассмотрим теперь включаемые в меню варианты. Существуют многочисленные рекомендации относительно того, как формировать варианты. Прежде всего отметим, что выбор метода 177
Рис. 6.5. Меню, в котором выбранный вариант указывается функ¬ циональной клавишей 178
идентификации вариантов до некоторой степени произволен. На рис. 6.2 каждому варианту предшествует номер. Варианты можно идентифицировать и буквами (рис. 6.4). При третьем способе идентификации варианты перечисляют с указанием соответ¬ ствующих им функциональных клавиш (рис. 6.5). Лично я предпочитаю пользоваться номерами и именно так будут обозна¬ чены варианты в данной главе. Поскольку номера вариантов соответствуют реальным действи¬ ям программы, они должны начинаться с числа 1. Вы, конечно, не раз видели меню, содержащие вариант с нулевым номером. Избегайте этого. Нуль всегда неявно предполагает отсутствие чего-то и в лучшем случае является абстракцией. Человечеству понадобилось много времени, чтобы изобрести нуль, и многие, встречаясь с ним, до сих пор испытывают трудности. Будьте добры, не затрудняйте работу пользователя, не пользуйтесь нулем без надобности. Буквы в качестве идентификаторов вариантов удобны в таких ситуациях, когда программа содержит небольшое число меню, и вы можете приписать вариантам мнемонически связанные с ними бук¬ вы. Пусть, например, пользователь нажимает клавишу «С», чтобы сложить, «И», чтобы изменить, и т. д. Пользователь склонен ожидать, что между идентификатором и соответствую¬ щим ему вариантом есть какая-то связь. Если между ними нет связи, то лучше обозначьте варианты цифрами. Функциональными клавишами в качестве идентификаторов ва¬ риантов меню пользоваться удобно, но при этом могут возник¬ нуть определенные сложности. Работа с меню предполагает, что интересующий вас вариант можно выбрать только в течение того времени, пока меню высвечивается ца экране. Пользователь не должен иметь возможности продолжать выбирать варианты работы программы после выхода из меню. Правда, некоторые методы управления программой, например метод управления с помощью специального языка, позволяют это делать. Но при стандартном использовании функциональных клавиш в языке BASIC они включаются операторами KEY(n) ON и ON KEY(n) GOSUB и остаются активными в любом месте программы. Если вы , хотите включить их только на время выдачи меню на экран, то в момент вывода кадра с меню их следует включать, а при выходе из меню — выключать. Однако это перегружает программу. Кроме того, обычно ожидается, что функциональные клавиши будут активны в течение всего времени работы программы или большей его части, и постоянное их включение и выключение противоречит обычным соглашениям. Вы должны взвесить все эти обстоятельства и решить, пользоваться ли вам функциональными клавишами для идентификации вариантов или нет. Если у вас есть какие-то сомнения, прибегните к другим способам. 179
В меню не следует включать более девяти вариантов. Идеаль¬ ное число вариантов заключается между пятью и семью. Это число придумал не я, оно было установлено в результате исследований. Меню, содержащее более девяти вариантов, стано¬ вится похожим на справочник. Требуется слишком много времени, чтобы его прочесть. Вам не приходилось работать с программами, меню которых содержали по 20—30 вариантов? Появление такого меню показывает, что программист не понимает, сколько времени уходит у людей на его чтение и поиск нужного варианта. Если в меню включено более пяти вариантов, то разумно раз¬ делить их список на две части пустой строкой (рис. 6.6). Такие меню легче читать. Желательно, чтобы тексты вариантов были краткими и содер¬ жательными. Если пользователь редко работает с программой, то предпочтительнее более длинные, но и более информативные тексты. Короткий текст варианта можно быстрее прочесть, но до¬ биться должной информативности короткого текста сложнее, чем длинного. Поэтому в редко используемых меню применяйте раз¬ вернутые тексты вариантов. Варианты меню можно формулиро¬ вать несколькими способами. • Кратко, по принципу «действие — объект»; формулируются действие и объект, с которыми будет работать пользователь. Например, обновить файл, покинуть программу, создать но¬ вый файл. • Путем краткого описания действия. Например, обновление файлов, завершение работы, создание нового файла. Описа¬ ниями могут служить наименования подпрограмм или неявные определения действий и объектов. Это менее четкая формулировка варианта работы программы, чем форма «действие — объект». • В виде длинных описаний варианта. Иногда они формули¬ руются в форме вопроса типа: «Не хотите ли вы обновить свои файлы?». Но могут просто описываться действия, на¬ пример: «Создание новых файлов и начало работы с ними». Мы перечислили только самые распространенные способы фор¬ мулировки вариантов. Трудно сказать, какой из них лучше — это зависит и от программы, и от пользователя. Ясно, что форму¬ лировка, в которой говорится, что и с каким объектом делать, понятнее, чем описательное название варианта, особенно для не¬ опытного пользователя. Длинные описания также понятные, но на их чтение уходит больше времени, поэтому такие описания лучше не употреблять в часто используемых программах. Я предпочитаю форму «действие — объект», как краткую и до¬ статочно информативную. Но какую бы форму вы ни выбрали, важно не смешивать ее с другими в одном меню и даже в одной программе. Это может запутать пользователя. 180
1. АНАЛИЗИРОВАТЬ ФАЙЛЫ 2. ОБНОВЛЯТЬ ФАЙЛЫ 3. ЗАПИСАТЬ ОПЕРАЦИЮ 4. ВЫЧИСЛИТЬ ДОХОД ИЛИ УБЫТОК 5. НАЧАТЬ НОВЫЙ ФАЙЛ 6. РЕДАКТИРОВАТЬ БАЗУ ДАННЫХ 7. ЗАПИСАТЬ ФАЙЛЫ 8. ИНИЦИАЛИЗИРОВАТЬ ДИСК Рис. 6.6. Длинное меню, в котором блок вариантов разбит на две части. Такое меню легче читать Рис. 6.7. Последний вариант, указываемый клавишей ESC, возвраща¬ ет программу к предыдущему меню 181
В программах, содержащих несколько связанных в одну сеть меню, часто бывает желательным включить в каждое из них одина¬ ковый завершающий вариант, возвращающий управление из этого меню в предыдущее. На рис. 6.7 изображено семейство иерархи¬ чески связанных друг с другом меню. Последний вариант каждого меню позволяет пользователю вернуться из текущего меню в пре¬ дыдущее. В данном примере такой вариант вызывается нажатием на клавишу ESC (отказ). «Глубоко погрузившийся» в программу пользователь может и не смотреть в меню, чтобы вернуться на предыдущий уровень; это всегда делается одинаково: доста¬ точно нажать клавишу ESC. Нажав ее повторно, пользователь возвратится еще на один уровень. Подсказка. Подсказка меню, как и любая другая подсказка о вводе данных, должна обратить внимание пользователя на тот факт, что программа ожидает ввода данных (для этого использу¬ ется мигающий курсор), и сообщить ему, что именно следует вводить. Подсказка может быть написана либо в краткой, либо в описательной форме, причем вполне приемлемы обе формы. При¬ ведем примеры описательных подсказок. • Наберите, пожалуйста, номер (или букву) выбранного ва¬ ми варианта. • Сообщите, пожалуйста, какой вариант вы выбрали. • Наберите номер подпрограммы, которую вы решили выпол¬ нить. Некоторые программисты вместо слова «наберите» (или «пожа¬ луйста, наберите») применяют термин «введите». Но такая форму¬ лировка не вполне точна. Слово «наберите» более конкретно, оно точнее описывает то, что на самом деле может делать пользо¬ ватель1. Я предпочитаю краткие подсказки такого типа: • Выбирайте. • Вариант. • Номер решения. Хотя такие подсказки не очень информативны, само меню од¬ нозначно определяет, что изображено на экране и что пользовате¬ лю следует набрать на клавиатуре. В любом случае, поработав с меню несколько раз, пользователь начинает игнорировать под¬ сказки. Вводимое пользователем сообщение о выбранном им по меню варианте должно появляться в строке подсказки. Программа не должна сразу же выполнять указанное действие. Пользователю надо дать возможность проверить и, если надо, изменить свое решение или, другими словами, подтвердить введенные им данные. 1 В отечественной литературе термин «наберите» практически не исгюльзу- ется.— Примеч. пер. 182
Для этого проще всего воспользоваться оператором INPUT. При работе этого оператора все, что набирает пользователь, высвечивается на экране, и пока не будет нажата клавиша «Ввод», ничего другого не происходит. Как отмечалось в гл. 5, этот оператор имеет недостаток: при его применении невниматель¬ ный или «злонамеренный» пользователь может полностью разру¬ шить изображение на экране дисплея. Поэтому лучше принимать данные с помощью оператора INKEY$ и верифицировать их с по¬ мощью клавиши «Ввод». Эта техника также описана в гл. 5. Используя этот оператор, вы сможете сохранить за программой управление изображением на экране, а также отфильтровывать вводимые с клавиатуры данные. Далее я покажу, как это делать. Дополнительная информация, которая может выдаваться на экран одновременно с меню. В некоторых случаях имеет смысл выдавать на экран дисплея некоторую дополнительную информа¬ цию. Особенно часто такая ситуация встречается в программах, активно использующих меню. При работе с указанными програм¬ мами пользователь почти всегда видит на экране какое-нибудь меню. В таких программах часто оказывается удобным выводить в одном кадре с меню некоторые сведения о состоянии программы и файлах, с которыми она работает. Включать подобные сведе¬ ния в кадры с меню имеет смысл только в том случае, если пользователь действительно в них нуждается на данном этапе работы, в противном случае они только загромождают кадр. Приведем примеры информации, которая может выводиться на экран одновременно с меню. • Объем свободной памяти. • Даты: текущее число, дата последнего обновления файла. • Имя обрабатываемого файла. • Объем свободной внешней памяти. Один из способов включить подобную информацию в меню — поместить ее в последнюю строку кадра, ниже строки подсказок. Тогда эта информация будет доступна, но никому не будет мешать. Пользователь обратится к ней, если захочет. ФОРМИРОВАНИЕ МЕНЮ, ЗАНИМАЮЩЕГО ВЕСЬ ЭКРАН Есть два основных способа формирования меню: непосредст¬ венный и с помощью подпрограммы. В первом случае меню генерируется таким же образом, как любой другой кадр вывода. Во втором случае программист задает только аргументы, а соб¬ ственно построение меню выполняется предназначенной для этого подпрограммой. Непосредственное формирование меню. Если в вашей програм¬ ме используется небольшое число меню, то, возможно, их лучше формировать непосредственно. Разметьте меню на бумажном 183
Рис. 6.8. Матрица проектирования бланке, как любой кадр вывода, а затем составьте порожда¬ ющий его фрагмент программы. На рис. 6.8 изображен бумажный бланк проектирования про¬ стого меню управления программой. Рис. 6.9 содержит програм¬ мный текст, создающий, строка за строкой, данное меню. Это меню было размечено на бланке так, чтобы блок вариантов был отцентрирован по вертикали, т. е. находился на примерно равном расстоянии от верхнего и нижнего края экрана. Кроме того, он отцентрирован и по горизонтали. Так как тексты вариантов имеют различную длину, центрировать блок вариантов по гори¬ зонтали не совсем просто. Приходится рассчитывать среднюю дли¬ ну текста вариантов, вычитать ее из переменной WIDE%, добав¬ лять 1 и делить на 2, т. е. использовать прием, который применялся для центрирования строки знаков на экране (см. подпрограмму, изображенную на рис. 4.16). Вычислив таким образом ширину левого поля, разместите тексты вариантов на бланке проектирования .кадра и посмотрите, как все это будет вы¬ глядеть. Если в вашем меню есть очень короткие и очень длинные строки, то может возникнуть впечатление, что блок вари¬ антов смещен влево от центра, так как мы склонны придавать больше значения длинным строкам, чем коротким. В таком случае сдвигайте блок до тех пор, пока кадр не станет выглядеть 184
простого меню управления программой как следует. Руководствуйтесь при этом соображениями эстетики. К сожалению, я не располагаю подпрограммой, которая сделала бы это за вас. Заголовок располагают в верхней части кадра. Если вам ка¬ жется, что он будет выглядеть лучше, если его сдвинуть на нес¬ колько строк вниз, сделайте это. Подсказка располагается в нижней части экрана. Вы можете переместить ее на несколько строк вверх. Если вы решите размес¬ тить под строкой подсказок дополнительную информацию, то, наверное, будет целесообразно сместить вверх все меню, чтобы кадр выглядел сбалансированно. Скорее всего с первого раза вам не удастся правильно разместить информацию в кадре. Программный текст, формирующий меню, изображен на рис. 6.9. Строка 10010 очищает экран. Строка 10020 определяет заго¬ ловок меню, а строка 40030 вызывает подпрограмму центри¬ рования и вывода на экран, начинающуюся в строке 1500. Строка 10050 перемещает курсор вниз, на строку 10, а строки 10060—10100 выводят, начиная с позиции 30, тексты пяти вариан¬ тов меню. Строки 10120—10210 выдают подсказку и принимают от пользователя данные. Строка 10120 перемещает курсор в нужную позицию, строка 10130 устанавливает режим инверсии изобра¬ жения, а строка 10140 выдает подсказку «Выбирайте!». 185
0 REM Программа (непосредственного) формирования меню 1 REM SAVE"A:FIG6-9. BAS" , А 960 WIDE’/. = 60 990 GOTO 10000 1500 1 1510 ' 1520 1 1530 ( 1540 1 1550 ( 1560 1 1 0000 10010 10020 10030 10040 10050 10060 10070 10060 10090 10100 101 10 10120 10130 10140 10150 10160 10170 10160 10190 10200 10210 10220 10230 REM--Центрирование и вывод заголовка- Т= (WIDE’Z + 1 -LEN (Тф) )/2 LOCATE ,T:REM COLOR 0,7: REM PRINT Тф COLOR 7,0:REM нормальное отображение RETURN I REH--Генератор полноэкранного меню-- I CLS I Тф="ГЛАВНОЕ МЕНЮ" I GOSUB 1500:REM печать заголовка I REM-Вывод вариантов- I LOCATE 10:REM расположить первый вариант в строке 10 I PRINT J PRINT I PRINT 1 PRINT J PRINT f REM-Вывод подсказки- f LOCATE 23, 35 J COLOR 0,7:REM инверсия PRINT"Выбирайте!"; COLOR 23,0:PRINT SPC(1) ; :REM мигающий курсор COLOR 7,0:REM нормальное отображение A$=INKEY$:IF Аф = "" GOTO 101?0 A=VAL(A$) IF A<1 OR A>5 THEN BEEP:GOTO LOCATE , POS(0)-1:PRINT Аф:REM Вф=1ИКЕ¥ф:IF B$="H GOTO 10210 IF ASC(Bi)<>13 GOTO 10110:REM END позиционирование курсора по горизонтали инверсия TAB(30)”1. TAB(30)«2. TAB (30) "3. TAB(30)"4. TAB(30)*5, Ввести данные" Создать новый файл" Напечатать отчет" Редактировать базу данных Покинуть программу" 10110 выдать на экран введенные данные подтверждено клавишей "Ввод"? Рис. 6.9. Программный текст, непосредственно формирующий изображенное на рис. 6.8 меню Строка 10150 выводит на экран мигающий курсор. Строка 10170 вводит один символ и присваивает его переменной A$i. Стро¬ ка 10180 преобразует его в численную переменную, а строка 10190 проверяет ее на попадание в заданный интервал значений. Если число лежит между 1 и 5 включительно, то оно пройдет проверку, в противном случае управление возвра¬ щается на строку ЮНО. Обратите внимание на то, что пользо¬ ватель должен будет продолжать ввод до тех пор, пока введенные им данные не попадут в правильный интервал. Неверные данные будут отфильтровываться. Как только будут введены правиль¬ ные данные, они будут выданы на экран строкой 10200. Наконец, строка 10210 введет символ подтверждения В$. Для этого должна быть нажата клавиша «Ввод»; в противном случае управление возвращается на строку 10110 и ввод начнется сначала. Формирование меню с помощью подпрограммы. Если вам надо подготовить более одного — двух меню, то скоро вам надоест раз¬ мечать их на бланке и составлять текст программы. Вы сохра- 186
ните много времени, если воспользуетесь подпрограммой, выпол¬ няющей за вас эту работу. Сложнее всего размещать и выводить на экран блок вариантов, центрируя его по вертикали и горизонтали. Но определение позиции блока сводится к простой арифметике, эти расчеты ваш ПК сделает молниеносно. На рис. 6.10 изображена распечатка подпрограммы, формиру¬ ющей полноэкранные меню, аналогичные изображенным на рис. 6.7. Аргументами подпрограммы служат переменные WIDE% (число столбцов), Т$ (текст заголовка), N (число допустимых 0 REM Подпрограмма формирования мейю (полноэкранного) 1 REH SAVE"A:FIG6-10. ВАЗ”, А 960 WIDEZ. = 80 990 GOTO 10000 1500 REM--Центрирование и вывод заголовка- 1510 Т=(WIDEZ+1-LEN(Тф))/2 1520 LOCATE ,T:REM позиционирование курсора по горизонтали 1530 COLOR 0,7:REM инверсия 1540 PRINT Тф 1550 COLOR 7,0:REM нормальное, отображение 1560 RETURN 4200 REM--Генератор полноэкранных меню-- 4210 CLS- 4220 Тф = " "+Т$+" МЕНЮ " 42 30 GOSUB .1500: REM печать заголовка 4240 REM-Вычисление начального столбца блока вариантов 4250 L=0 4260 FOR А=1 ТО N 4270 LiL+LEN(ОРТф(А))+3 4260 NEXT .4290 LcL/N 4300 Н=(WIDEZ+1-L)/2:REM вычисление позиции табулирования 4310 REM-Вычисление смещения по вертикали •4320 Vz (26-N)/2 4330 REM-Вывод вариантов- 4340 LOCATE V:REM расположить первый вариант 4350 FOR А-1 ТО N 4360 PRINT TAB (Н-1 ) STR$ (А)..; ". "ОРТф (А) 4370 NEXT 4380 REM-Вывод подсказки- 4390 LOCATE 23, 35 4400 COLOR 0,7:REM инверсия 4410 PRINT"Выбирайте•" ; 4420 COLOR 2 3, 0: PR I NT SPC (1) *; : REM • мигающий курсор 4430 COLOR 7,0:REM нормальное отображение 4440 A|=INKEYi:IF A$="" GOTO 4440 4450 A-VAL(A|) 4460 IF A<1 OR A>N THEN BEEP:GOTO 4380 4470 LOCATE ,POS(0)-1:PRINT A$:REM выдать на экран введенные данные 4460 B|:INKEYi:IF В|="м GOTO 4480 4490 IF ASC(b|)<>13 GOTO 4380:REM подтверждено клавишей "Ввод"? 4500 RETURN 10000 REM--формирование меню- 10010. N:5 10020 Тф= "ГЛАВНОЕ" 10030 ОРТф(1)-"Введти данные" 1.0040 ОРТф (2) z "Создать новый файл" 10050 ОРТф(3)="Напечатать отчет" 10060 ОРТф(4)="Редактировать базу данных" 10070 ОРТф(5)-"Покинуть программу" 10060 GOSUB 4200 10090 END Р и с. 6.10. Подпрограмма формирования полноэкранных меню с пронумерованными вариантами (строки 4200—4500) 187
вариантов, имеющих номера от 1 до N) и ОРТ$(1)—OPT$(N) (тексты вариантов). Чтобы воспользоваться этой подпрограммой (как, впрочем, и любой другой), следует сначала определить значения аргумен¬ тов, а затем с помощью оператора GOSUB вызвать саму подпрограмму. Эта работа осуществляется в строках 10000—10080 программы, см. рис. 6.10. После вызова подпрограмма очищает экран и формирует меню. Она выводит заголовок в верхней строке, вычисляет среднюю длину текста вариантов и центрирует блок вариантов сначала по горизонтали, а затем исходя из числа вариантов и по вертикали и, наконец, выводит подсказку в строке 23. По меньшей мере сомнительно, что вам понравится меню с заголовком в верхней строке, а подсказкой в нижней. В боль¬ шинстве случаев меню будет выглядеть лучше, если три его части приблизить друг к другу. Подпрограмму, приведенную на рис. 6.10, легко модифицировать с тем, чтобы изменить расположе¬ ние различных компонент меню. К варианту этой подпрограммы следует относиться как к отправной точке для подготовки подпро¬ граммы формирования меню, удовлетворяющей вашим потреб¬ ностям. Рассматриваемая подпрограмма основана на разобранном ранее программном тексте, изображенном на рис. 6.9, так что остановимся прежде всего на различиях между ними. На рис. 6.10 строки 4220—4230 формируют заголовок. В строках 4250— 4290 вычисляется средняя длина (L) текстов вариантов. В строке 4250 переменной L присваивается начальное значение 0. Затем в строках 4260—4280 суммируется длина текстов всех вариантов с учетом трех позиций: номера, точки и пробела, которые будут расположены перед текстами вариантов. Далее в строке 4290 полученная сумма делится на число вариантов (N): в ре¬ зультате определяется средняя длина варианта. В строке 4300 вы¬ числяется позиция элементов меню по горизонтали (Н), начиная с которой будут выводиться тексты вариантов. В строке 4320, исходя из числа вариантов, вычисляется смещение пер¬ вого варианта по вертикали. Строка 4340 позиционирует курсор по вертикали, а строки 4350—4370 выводят тексты вариантов, добавляя к ним спереди номер, точку и пробел. Для учета пробела, который добавля¬ ется в системе BASIC при преобразовании числа в строку символов, из позиции табулирования Н вычитается единица. Строки 4390—4490 выводят подсказку и принимают данные. Эти строки отличаются от соответствующих строк на рис. 6.9 но¬ мерами, а также тем, что для проверки на ошибки в строке 4460 вместо константы 5 используется число N. Если у программиста есть такая подпрограмма, его работа по построению меню фактически сводится к набору на клавиа¬ туре строк, содержащих ее аргументы. В рассмотренном примере 188
восемь строк программного текста, определяющего аргументы и вызывающего подпрограмму, позволили сформировать пятивари¬ антное меню, изображенное на рис. 6.7. Эта подпрограмма существенно экономит время программиста, избавляя его от нуд¬ ного подсчета знаков в текстах вариантов и вычисления позиции элементов меню по горизонтали и по вертикали. ПЕРЕКЛЮЧЕНИЕ УПРАВЛЕНИЯ Формирование меню, осуществляемое непосредственно или с помощью подпрограммы, это лишь подготовка кадра выдачи. Для управления программой необходимо выбор пользователя пре¬ образовать в управляющее воздействие. Проще говоря, если пользователь, нажав клавиши «1» и «Ввод», выберет первый вариант, то вы должны передать управление фрагменту про¬ граммы, выполняющему соответствующую функцию. В данном параграфе демонстрируются два способа переключения управле¬ ния, использующие операторы языка BASIC: логика IF—THEN и оператор ON X GOTO. Кроме того, будет показано, с какой целью и каким образом эти два способа комбинируют. Приведенные ниже примеры основаны на описанной в предыдущем параграфе подпрограмме формирования меню, хотя рассматри¬ ваемые методы переключения управления программой равно применимы и тогда, когда меню формируется непосредственно. Строка 4440 подпрограммы формирования меню (см. рис. 6.10) вводит номер варианта работы программы, выбранного пользова¬ телем по меню, и присваивает его строковой переменной А$. Строка 4450 преобразует эту переменную в число и при¬ сваивает результат действительной переменной А. Итак, подпро¬ грамма возвращает значение номера варианта в двух формах, обе из которых можно использовать при переключении управления. Отметим также, что, поскольку подпрограмма контролирует введе¬ нные данные, ею возвращаются только допустимые значения переменных А и А$, поэтому в дальнейшем их контроле нет необходимости. Логика IF—THEN. Предположим,что ваше меню содержит пять вариантов, изображенных на рис. 6.7, и что соответствую¬ щие фрагменты программы начинаются в следующих строках: 1. Ввод данных . . . 12000 2. Создание, нового файла. 14000 3. Печать отчета 20000 4. Редактирование базы данных 24000 5. Завершение работы программы 10500 Вы можете переключать управление с помощью логики IF—THEN, вставив в изображенный на рис. 6.10 текст программы следующие строки: 10090 REM — УПРАВЛЕНИЕ ПРОГРАММОЙ — 10100 IF А = 1 GOTO 12000 189
10110 IF А = 2 GOTO 14000 10120 IF А = 3 GOTO 20000 10130 IF A = 4 GOTO 24000 10140 IF A = 5 GOTO 10500 В этом тексте для управления использовалась действительная переменная А. Но можно воспользоваться этой переменной в стро¬ ковой форме: 10090 10100 10110 10120 10130 10140 IF IF IF IF IF REM — УПРАВЛЕНИЕ ПРОГРАММОЙ — Ad>=- ’T’GOTO 12000 AJ>= ”2” GOTO 14000 AS = ”3”GOTO 20000 AS= ”4” GOTO 24000 A$= ”5” GOTO 10500 Вполне допустимо использование в одной программе перемен¬ ной, управляющей переключателем и в действительной, и в строко¬ вой форме: 10090 REM — УПРАВЛЕНИЕ ПРОГРАММОЙ — 10100 IF А=1 GOTO 12000 10110 IF А = 2 GOTO 14000 10120 IF А$= ”3” GOTO 20000 10130 IF A$ = ”4” GOTO 24000 10140 IF A$=”5”GOTO 10500 Может показаться, что в этом нет никакого смысла, но позднее мы увидим, что иногда это бывает удобно. Поставленную задачу решат все три варианта программы, но первый наиболее экономичен. Тем не менее и он требует пяти операторов, по оператору на каждый включенный в меню вариант. Оператор ON X GOTO. Оператор ON X GOTO намного эконо¬ мичнее логики IF — THEN. Этот оператор передает управление на Х-й из номеров строк, записанных после слова GOTO. Например, только что приведенная логика переключения управле¬ ния может быть сведена к одному оператору: 10100 ON A GOTO 12000, 14000, 20000, 24000, 10500 Очевидно, что этот оператор намного короче, но он требует, чтобы X обязательно было числом. Использование в позиции X данных строкового типа недопустимо. Кроме того, если X равно нулю или числу, которое больше, чем количество следующих за словом GOTO аргументов, то управ¬ ление передается следующей за этим оператором строке. На¬ пример, при выполнении такой программы: ю х=о 20 ON X GOTO 40. 50. 60 30 PRINT ’’Строка 30”: END 40 PRINT ’’Строка 40”: END 50 PRINT ’’Строка 50”: END 60 PRINT ’’Строка 60”: END управление перейдет на строку 30. То же. самое произойдет, если X будет больше трех. 190
Совместное использование цифровых и буквенных идентифи¬ каторов вариантов. Иногда бывает целесообразно использовать в одном меню цифровые и буквенные идентификаторы вариантов. Предположим, к примеру, что мы хотим запрограммировать меню со следующими четырьмя вариантами: 1. Ввести данные 2. Создать новый файл 3. Напечатать отчет ESC. Завершить работу программы Для создания такого меню подпрограмму его формирования придется изменить так, чтобы, кроме текстов вариантов, она поз¬ воляла определять и их идентификаторы (числа или буквы, пред¬ шествующие названию). Тогда перед названием варианта можно будет выводить не только номер, а все, что угодно. Кроме того, фрагмент подпрограммы, выполняющий контроль входных данных, следует изменить таким образом, чтобы он допускал значение переменной А, равное нулю. Такое значение А получит в том слу¬ чае, если будет нажата нецифровая клавиша. На рис. 6.11 в строках 4200—4500 приведена модифицирован¬ ная версия подпрограммы формирования меню, обеспечивающая указанные возможности. В исходной версии были изменены следу¬ ющие строки: 4720— Вычисление длины текста вариантов основано только на ОРТ$(А), поскольку теперь в этой строке содержится весь текст варианта (ранее к длине текста добавлялось число 3 для учета номера, точки и пробела, которые предшествовали собственно тексту варианта). 4360— ТАВ(Н—1) заменено на ТАВ(Н), так как теперь число не преобразуется в строку. 4455— Это строка добавлена для того, чтобы обеспечить воз¬ можность возврата из подпрограммы при значении А, равном нулю. Переменная А равна нулю, если пользова¬ тель ввел 0 или нажал нецифровую клавишу. Поскольку подобные значения А могут соответствовать ошибочно введенным данным (А$), они подлежат дальнейшему контролю вне рассматриваемой подпрограммы. Обрати¬ те внимание, что вводимые данные не подтверждаются нажатием на клавишу «Ввод». 4460— Аргумент N, определявший максимальное число вари¬ антов в меню, заменен на N0; благодаря этому число вариантов может превышать число допустимых номе¬ ров. Например, в только что показанном меню имеется четыре варианта, но только три допустимых номера (1-3). В строках 10000—10080 содержится программный текст, по¬ рождающий данное меню на экране. В строке 10010 определяется число вариантов в меню (N), а в строке 10020 — число вариан- 191
REM--Центрирование и вывод заголовка- Т = (WIDE7. + 1 -LEN (Тф) ) / 2 LOCATE ,Т:REM COLOR 0,7: REM PRINT T| COLOR 7,0;REM RETURN REM--Генератор полноэкранных меню-- CLS . T|=" "+T|+" МЕНЮ " GOSUB 1500:REM печать заголовка REM-Вычисление начального столбца блока вариантов L = 0 FOR А-1 ТО N L=L+LEN(ОРТф(А)) NEXT L=L/N Н= (WIDE7.+-1-L)/2: REM вычисление позиции табулирования REM-Вычисление смещения по вертикали v=(26-NJ/2 REM-Вывод вариантов- LOCATE V:REM расположить первый вариант FOR Axl ТО N позиционирование курсора по горизонтали инверсия нормальное отображение 0 REM Подпрограмма Формирования меню (полноэкранного) 1 REM SAVE"A: FIG6-11 .’BAS", А 960 VI DEX = 60 990 GOTO 10000 1500 1510 1520 1530 1540 1550 1560 4-200 4210 4220 4230 4240 4250 4260 4270 4260 *4290 4300 4310 4320 •4330 4340 4350 4360 PRINT TAB(H)OPT$(A) 4370 4360 4390 4400 4410 4420 4430 4440 4450 4455 IF A=0 GOTO 4500 4460 IF A<1 OR A>N0 THEN BEEP:GOTO 4360 4470 LOCkTE ,POS(0)-1:PRINT A|:REM выдать на экран введенные данные 4460 B$:INKEY|:IF В$="" GOTO 4460 4490 IF•ASC(Вф)<>13 GOTO 4360:REM подтверждено клавишей "Ввод"? 4500 Г 10000 10010 10020 10030 10040 10050 10060 10070 10060 10090 10100 10110 10120 10130 10140 NEXT REM-Вывод подсказки- LOCATE 23,35 COLOR 0,7:REM инверсия PRINT"Выбирайте’ "; COLOR 2 3,0: PR I NT SPC(1) :REM мигающий курсор COLOR 7, 0: REM нормальное отображение A$=INKEY$:IF Ai="" GOTO 4440 A=VAL(A$) RETURN i REM--формирование меню— ( N=4 I N0=3 f T$="ГЛАВНОЕ" > OPT$ (1 ) z ".1 - I OPT$(2)z"2 - I OPT|(3)="3 - I OPTi(4)="ESC ( GOSUB 4200 I IF A=1 GOTO I IF A=2 GOTO 1 IF . I IF ASC(A$)=27 GOTO 10140:REM нажата клавиша "ESC1 I GOTO 10010 I CLSt END:REM конец программы Ввести данные" Создать новый файл" Напечатать отчет" - Покинуть программу' А:3 GOTO 12000:REM клавиша "1" 14000:REH клавиша "2" 16000:REM клавиша "3" Р и с. 6.11. Подпрограмма формирования полноэкранных меню с любы¬ ми идентификаторами вариантов (строки 4200—4500 представляют аль¬ тернативу программе, изображенной на рис. 6.10) 192
тов с номером (N0). В строке 10030 задается текст заголовка меню, а в строках 10040—10070—тексты четырех вариантов, сос¬ тавляющих меню. Строка 10080 вызывает подпрограмму. Для управления работой программы используется логика IF—THEN. Строки 10090—10120 следят соответственно за клави¬ шами 1, 2, 3 и ESC. Если ни одна из этих клавиш не была нажа¬ та, то строка 10130 возвратит управление на строку 10080, которая сформирует меню повторно. Сети управления, использующие меню. Термин сеть используют для обозначения структуры, образующейся при соединении после¬ довательности меню. На рис. 6.12 изображен пример простой трех¬ уровневой иерархической сети. Подобный тип сети называется деревом. Каждое меню (или узел дерева) соединено только с одним меню верхнего уровня и, возможно, с несколькими меню следую¬ щего уровня. Чем дальше мы продвигаемся по дереву, тем большее число меню отделяет нас от меню самого верхнего уровня. Рис. 6.12. Простая иерархическая трехуровневая сеть меню, имеющая форму дерева Древовидные структуры широко применяются в программах для ЭВМ. Они предоставляют доступ к любой части программы, а простота этой структуры облегчает ее освоение. Но древо¬ видные структуры имеют один недостаток. В большой многоуров¬ невой сети на переход от одной подпрограммы к другой уходит много времени, в особенности если эти подпрограммы распо¬ ложены на разных ветвях сети. Чтобы, например, перейти из 7 Зак. 1488 193
0 REM Текст программы сети меню 1 REM-SAVE"A:FIG6-13. BAS" , А 980 WIDEZ=80 990 GOTO 10000 1500 REM--Центрирование и вывод заголовка- 1510 Т=(WIDEZ+1-LEN(Т$))/2 1520 LOCATE , T:REM позиционирование курсора по горизонтали 1530 COLOR 0, 7: REM инвёрсия 1540 PRINT Т$ 1550 COLOR 7,0:REM нормальное отображение 1560 RETURN 4010 REM--Пауза-- 4020 LOCATE 23,WIDEZ/2-23 4030 COLOR 16,7:REM режим мигающего инвертированного отображения 4040 PRINT"[Для продолжения работы нажмите клавишу пробела]"; 4050 COLOR 7,0:REM режим нормального отображения 4060 A$=INKEY|:IF А$<И " GOTO 4060 4070 PRINT 4060 RETURN 4200 REM--Генератор полноэкранных меню-- 4210 CLS 4220 Т$=" "+Т$+" МЕНЮ " 4230 GOSUB 1500:REM печать заголовка 4240 REM-Вычисление начального столбца блока вариантов 4250 L=0 4260 FOR А=1 ТО N 4270 LcL+LEN(ОРТф(А)) 4280 NEXT 4290 L=L/N 4300 Н= (WIDEZ + 1-L*)/2: REM вычисление позиции табулирования 4310 REM-Вычисление смещения по вертикали 4320 V=(26-N)/2 4330 REM-Вывод вариантов- 4340 LOCATE V:REM расположить первый вариант 4350 FOR Ас 1 ТО N 4360 PRINT TAB(Н)ОРТ$(А) 4370 NEXT 4380 REM-Вывод подсказки- 4390 LOCATE 23, 35 4400 COLOR 0,7:REM инверсия 4410 PRINT"Выбирайте! 4420 COLOR 23,0:PRINT SPC(1) :REM мигающий курсор 4430 COLOR 7,0:REM нормальное отображение 4440 A$=INKEY|:IF A$="" GOTO 4440 4450 A=VAL(A$) 4465 IF A=0 GOTO 4500 4460 IF A<1 OR A>N0 THEN BEEP GOTO 4380 4470 LOCATE ,POS(0)-1:PRINT As:REM выдать на экран введенные данные 4460 B$=INKEY$:IF Вф="" GOTO 4460 4490 IF ASC(B|)<>13 GOTO 4380:REM подтверждено клавишей "Ввод”? 4500 RETURN 10000 REM--Главное меню-- 194
10010 N-3 10020 N0=2 10030 T|="ГЛАВНОЕ" 10040 ОРТф(1)="1 - Альфа" 10050 ОРТ|(2)="2 - Бета" 10060 OPT|(3)="ESC - Покинуть программу" 10070 GOSUB 4200 10080 IF А =1 GOTO 12000 10090 IF к-2 GOTO 19000 10100 IF ASC(A$)=27 THEN CLS;END:REH конец программы 10110 GOTO 10010 12000 REM--Meню Альфа- 12010 N=3 12020 N0=2 12030 T$="АЛЬфА" 12040 ОРТ$(1 ) = " 1 - Чарли" 12050 ОРТ$(2)="2 - Дельта" 12060 OPT$(3)="ESC - Возврат" 12070 GOSUB 4200 12060 IF А=1 GOTO 13000 12090 IF А=2 GOTO 16000 12100 IF ASC(A$)=27 GOTO 10000 12110 GOTO 12010 13000 REM--Меню Чарли-- 13010 N=3 13020 N0=2 13030 T|="ЧАРЛИ" 13040 ОРТф(1)="1 - кадр С1" 13050 ОРТф(2)="2 - кадр С2* 13060 ОРТф(3)="ЕБС - Возврат" 13070 GOSUB 4200 13060 IF А=1 THEN GOSUB 14000 13090 IF A=2 THEN GOSUB 15000 13100 IF ASC(A$)=27 GOTO 12000 13110 GOTO 13010 14000 REM--Кадр C1-- 14010 CLS 14020 Тф="КАДР Cl" 14030 GOSUB 1500 14040 GOSUB 4010 14050 RETURN 15000 REM--Кадр C2-- 15010 CLS 15020 Тф="Кадр C2" 15030 GOSUB 1500 15040 GOSUB 4010 15050 RETURN 16000 REM--Меню Дельта-- 16010 N=3 16020 N0=2 16030 Тф="ДЕЛЬТА" 16040 0РТф(1)="1 - кадр D1" 16050 ОРТф(2)="2 - кадр D2" 16060 0PT$(3)="ESC - Возврат" 16070 GOSUB 4200 16080 IF А=1 THEN GOSUB 17000 16090 IF А=2 THEN GOSUB 18000 16100 IF ASC(A|)=27 GOTO 12000 16110 GOTO 16010 17000 REM--Кадр DI - - 17010 CLS 17020 Тф="КАДР DI" 7* 195
17030 GOSUB 1500 17040 GOSUB 4010 1.7050 RETURN 13000 REM—Кадр D2 - - 13010 CLS 13020 Т$=”КАДР D2” 18030 GOSUB 1500 18040 GOSUB 4010 18050 RETURN 19000 REM--Меню Бета-- 19010 N=3 19020 N0=2 19030 Тф=”БЕТА” 19040 ОРТф( 1 ) = ” 1 - ЭХО” 19050 ОРТф(2)="2 - фокстрот" 19060 OPT|(3)="ESC - Возврат" 19070 GOSUB 4200 19030 IF A-1 GOTO 20000 19090.IF A-2 GOTO 23000 19100 IF ASC(A|)=27 GOTO 10000 19110 GOTO 19010 20000 REM--Меню Эхо-- 20010 N=3 20020 N0=2 20030 Тф=”ЭХО” 20040 ОРТф(1)-”1 - кадр El" 20050 ОРТф(2)=”2 - кадр Е2" 20060 ОРТ$ (3)--"ESC - Возврат” 20070 GOSUB 4200 20080 IF А=1 THEN GOSUB 21000 20090 IF A--2 THEN GOSUB 22000 20100 IF ASC(A|)=27 GOTO 19000 20110 GOTO 20010 21000 REM--Кадр E1-- 21010 CLS 21020 Тф="КАДР El” 21030 GOSUB 1500 21040 GOSUB 4010 21050 RETURN 22000 REM--KaflP E2-- 22010 CLS 22020 Тф=”КАДР E2" 22030 GOSUB 1500 22040 GOSUB 4010 22050 RETURN 23000 REM--Меню фокстрот-- 23010 N--3 23020 N0=2 23030 Тф="ФОКСТРОТ” 23040 ОРТф(1)=”1 - кадр F1” 23050 ОРТф(2)=”2 - кадр F2” 23060 OPTi(3)=”ESC -Возврат” 23070 GOSUB 4200 23080 IF А=1 THEN GOSUB 24000 23090 IF A=2 THEN GOSUB 25000 23100 IF ASC(A$)=27 GOTO 19000 23110 GOTO 23010 24000 REM--Кадр F1-- 24010 CLS 24020 Тф="КАДР Fl” 24030 GOSUB 1500 24040 GOSUB 4010 24050 RETURN 25000 REM--Кадр F2-- 25010 CLS 25020 Тф=”КАДР F2” 25030 GOSUB 1500 25040 GOSUB 4010 25050 RETURN Рис. 6.13. Программный текст, необ¬ ходимый для формирования меню и фиктивных кадров сети управления программой, изображенной на рис. 6.12 меню Дельта в меню Фокстрот, пользователь должен пройти через три других меню: меню Альфа, главное меню и меню Бета. С помощью подпрограммы формирования меню (см. рис. 6.11) довольно легко составить программный текст, порождающий сеть меню, аналогичную изображенной на рис. 6.12. Эта сеть содержит семь меню, тем не менее программирование этих меню и связей между ними займет примерно то же время, какое потребу¬ ется для записи их аргументов, вызовов подпрограмм и управ¬ ляющей логики, т. е. примерно час — два рабочего времени про¬ граммиста средней квалификации. На рис. 6.13 представлен программный текст, формирующий все меню, а также восемь фиктивных кадров вывода. Возможно, вы сочтете полезным для своего обучения набрать и испытать этот текст. Приведенный пример показывает, как быстро можно соста¬ вить сеть правильно оформленных меню. Главное меню формируется в строках 10000—ЮНО. Это меню связано с меню Альфа (строки 12000—12110) и Бета (19000— 196
19110). Меню Альфа соединено с меню Чарли (строки 13000— 13110) и Дельта (16000—16110). Аналогично меню Бета связано с меню Эхо (строки 20000—20110) и меню Фокстрот (23000— 23110). Каждое из четырех меню третьего уровня — Чарли. Дель¬ та, Эхо и Фокстрот — соединено дополнительно с двумя фиктив¬ ными кадрами вывода. Совместно с этими меню используется управляющая логика IF—THEN, позволяющая пользователю переходить на следующий уровень меню, нажимая цифровую клавишу, или возвращаться на предыдущий уровень, нажимая клавишу ESC. Вследствие того что на передвижение по ветвям сети типа изображенной на рис. 6.12 уходит много времени, программисты часто ее модифи¬ цируют, обеспечивая быстрый возврат в главное меню. Получаю¬ щаяся в результате сеть выглядит так, как показано на рис. 6.14. Во все меню программы, кроме главного, добавляется вариант возврата в главное меню. Конечно, в некоторые меню можно добавить варианты, позво¬ ляющие быстро перемещаться в другие части программы. Но при этом необходимо быть осмотрительным, ведь сеть меню во многом определяет логику вашей программы. Если она хорошо спроекти¬ рована и ее подпрограммы связаны друг с другом естественным образом, то не потребуется делать много «заплат», соединяющих различные части программы. Каждая связь в сети подобна опера¬ тору GOTO в самом тексте программы. Если работа этих операто¬ ров (GOTO) организована по некоторой схеме, то структуру вашей Рис. 6.14. Трехуровневая иерархическая сеть меню, в которой из всех меню, даже находящихся на самом нижнем уровне, имеется прямой путь в главное меню 197
программы будет легче проследить. Если связи между меню произвольны и неорганизованны, то сеть меню становится подоб¬ ной тексту программы, написанной без всяких правил, по «мака¬ ронной» логике1. Как следует «опасаться GOTO» при составлении текста программы, так следует опасаться и беспорядочного соединения меню. Кроме дерева существуют и другие организации сетей. Можно, например, построить сеть, имеющую вид звезды (рис. 6.15, Л), матрицы (рис. 6.15, В) или другой специальный вид. В звезде обычно имеется одно меню, в котором перечисляются все варианты. Такое меню может стать очень длинным, но если его варианты независимы, т. е. не связаны друг с другом каким- нибудь иерархическим образом, то организация программы в виде сети — звезды может оказаться целесообразной. Матрица допускает практически произвольные связи между меню. В некоторых программах это может оказаться полезным, но изучать и использовать такие программы крайне трудно. В самом деле, идеальной структуры управления, которая была бы пригодна для любых программ, не существует, так как струк¬ тура управления должна быть спроектирована исходя из взаимо¬ связей между различными функциями программы. Часто такие взаимосвязи оказываются иерархическими. Если это так, то в ка¬ честве структуры управления естественно принять дерево. Струк¬ тура управления должна следовать из логики программы, а не предписывать эту логику. Для определения структуры проанали¬ зируйте подпрограммы, кадры вывода, функции программы и вы¬ полняемые ею работы. Объедините взаимосвязанные компоненты. Найдите иерархические связи между ними. Затем спланируйте сеть. Приведем несколько рекомендаций по организации сетей. • По возможности, используйте иерархические сети. Ф Старайтесь не допускать, чтобы в одном меню было больше девяти вариантов. • Если сеть меню состоит из трех или более уровней, введи¬ те в каждое меню вариант, возвращающий управление на самый верхний уровень сети (в главное меню). • Как правило, лучше проектировать сеть с меньшим числом уровней и большим числом вариантов в каждом меню, чем наоборот. Если, например, ваша программа выполняет 64 функции, то лучше иметь два уровня меню с восьмью вариан¬ тами в каждом (рис. 6.16), чем трехуровневую сеть с четырь¬ мя вариантами (рис. 6.17) или шестиуровневую сеть с двумя вариантами в каждом меню (рис. 6.18). 1 Термин «макаронная» логика («логика спагетти») означает организацию программ, характеризуемую многочисленными запутанными передачами управле¬ ния (как правило, реализованными с помощью оператора GOTO). Такие программы очень трудно сопровождать. Альтернативой «макаронной» логике являются правила структурного программирования. — Примеч. пер. 198
А ВАРИАНТ ВАРИАНТ F ВАРИАНТ В ГЛАВНОЕ МЕНЮ ВАРИАНТ Е ВАРИАНТ ВАРИАНТ С ВАРИАНТ А ■Q ВАРИАНТ D ВАРИАНТ В ■Q ВАРИАНТ Е Q ВАРИАНТ С ^ВАРИАНТЕ Рис. 6.15. Сети управления программой, имею¬ щие форму (А) звезды и (В) матрицы Рис. 6.16. Сеть управления программой, имеющая два уровня меню (глу¬ бина =2), каждое из которых содержит по восемь вариантов (ширина = 8) 199
Рис. 6.17. Сеть управления программой, имеющая три уровня меню (глуби¬ на =3), каждое из которых содержит по четыре варианта (ширина = 4) Рис. 6.18. Сеть управления программой, имеющая шесть уровней меню (глу¬ бина =6), каждое из которых содержит по два варианта (ширина = 2) 200
МЕНЮ, ЗАНИМАЮЩИЕ ЧАСТЬ ЭКРАНА Меню, занимающие часть экрана, обычно размещаются в не¬ большом числе строк. Как минимум такое меню занимает одну строку, но может занять и несколько строк (рис. 6.19, 6.20 и 6.21). Как говорит само их название, такие меню использу¬ ют только часть экрана. Эти меню применяются для манипулиро¬ вания изображением, управления вводом данных и других дейст¬ вий, имеющих отношение к информации, отображаемой в том же кадре вывода. Этим они и отличаются от полноэкранных меню. Последние обычно явно прерывают последовательность кадров вывода. Пока они находятся на экране, другая информация не вы¬ водится. Другое отличие между двумя типами меню связано с их применением. Меню, занимающие часть экрана, обычно действуют локально и относятся к конкретному кадру. Они позволяют пользо¬ вателю управлять этим кадром. Полноэкранные меню, как прави¬ ло, решают в программе глобальные задачи и обеспечивают переход от одной части программы к другой. На рис. 6.19 изображено меню, занимающее часть экрана. Оно дает возможность добавить, изменить или удалить информацию, а также выйти из кадра. Это меню имеет следующие характерис¬ тики: • Меню занимает две строки в нижней части экрана. • Оно выдается в режиме инверсии изображения. • Варианты меню идентифицируются буквами, выбранными исходя из соображений мнемоники. • Меню воспринимает нажатие на отдельные клавиши; для приема соответствующих сигналов используется оператор INKEY$. • Меню не озаглавлено. • Подсказка отсутствует. В такое меню легко включить заголовок и подсказку. Будет ли это сделано, зависит главным образом от наличия на экране места. Поскольку основной интерес представляет не меню, а высве¬ чиваемая на экране информация, часто оказывается желательным придать меню максимально сжатую форму. При этом, возможно, придется пожертвовать заголовком и подсказкой, а названия ва¬ риантов ограничить одним словом. Такие меню могут появляться почти в любом месте экрана и иметь почти любой вид. На рис. 6.20 изображено меню, сжатое не по вертикали, а по горизонтали и выведенное в правом поле экрана. Это меню применяется для управления графическим изображением, выдаваемым в центральной части экрана. Наконец, на рис. 6.21 изображено меню, расположенное в вер¬ хней части экрана. Как правило, это место неудобно для размещения меню, так как оно «принадлежит» заголовку. Но в некоторых случаях и такое расположение меню имеет смысл. 201
Рис. 6.19. Меню, занимающее часть экрана и состоящее из двух строк в нижней части кадра Рис. 6.20. Меню, занимающее часть экрана и состоящее из блока вариантов, расположенных у правого края кадра 202
Рис. 6.21. Меню, занимающее часть экрана и состоящее из одной строки в верхней части кадра Во всех примерах идентификатор варианта меню со¬ стоит из одной буквы. В качестве идентификатора можно использовать и цифры, но все же в меню такого рода предпоч¬ тение лучше отдать буквам. Идентификаторы должны быть свя¬ заны по смыслу с названием варианта. Формат меню (на¬ пример, блок вариантов, выдаваемый в режиме инверсии с мигающим курсором на правом крае) проектируется в расчете на его легкое распознавание даже без заголовка и подсказки. Конечно, меню можно спроектировать и без инверсии изобра¬ жения или мигающего курсора, но без этих визуальных сиг¬ налов пользователю будет труднее выделить его на экране. В представленных на рис. 6.19—6.21 меню идентификаторы вариантов связываются с их текстами тремя различными способа¬ ми: буквой в скобках (рис. 6.19) — <Д> Добавить; знаком равенства (рис. 6.20) —В = Вращать; большой буквой на фоне малых (рис. 6.21) —вЫйти. Все три способа достаточно эффективны. Но если вы выбрали ка¬ кой-то метод, то придерживайтесь его во всей программе. Любое из этих меню довольно просто построить и непосредст¬ венно, и с помощью подпрограмм. Приведу пример, как это сделать с помощью подпрограммы. Эту подпрограмму вы можете легко из¬ менить с учетом ваших требований. Она позволяет сформиро¬ 203
вать меню, содержащее до 24 строк, в любом месте экрана. Меню выводится в режиме инверсии. Подпрограмма изображена на рис. 6.22. Ее аргументами являются переменные WIDE% (число столб¬ цов)^ (начальная строка), Н (начальный столбец), N (число строк) и ОРТ$ (1)—OPT$(N) (тексты строк меню). Она состоит из строк с номерами 4600—4740. Поскольку данная подпрограмма предназначена для формиро¬ вания меню разных размеров, число строк меню (N) переменно. Для управления количеством стираемых и вводимых на экран строк в подпрограмме используется цикл FOR — NEXT. Этот цикл начинается в строке 4610 и завершается в строке 4690. Строка 4630 очищает строку экрана, строка 4640 помещает курсор в начало строки, а строка 4660 выводит А-ю строку меню в инвертированном отображении. Затем строка 4680 увеличивает V на единицу, благодаря чему при следующем выполнении цикла FOR — NEXT строка меню будет стираться и выдаваться в пра¬ вильной позиции кадра. Строка 4700 выводит мигающий курсор, строка 4720 вводит одиночный символ А$, а строка 4730 выдает этот символ на экран. Обратите внимание, что эта подпрограмма не позволяет пользователю верифицировать введенный им символ. Для иллюстрации того, как работает эта подпрограмма, были написаны строки 10000—10060, содержащие операторы присвое- 0 REM Подпрограмма формирования меню (часть экрана) 1 REM SAVE"A:FIG6-22", А 980 WIDEZ=80 990 GOTO 10000 4600 : 4610 ] 4620 1 4630 ] 4640 ] 4650 I 4660 ] 4670 < 4680 1 4690 ] 4700 I 4710 < 4720 . 4730 1 4740 ] 1 0000 10010 10020 10030 10040 10050 10060 10070 REM--Генератор меню, занимающих часть экрана-- FOR А= 1 ТО N LOCATE V, H:REM позиционируем курсор PRINT SPACES(WIDEZ+1-Н);:REM стираем до конца строки LOCATE V, H:REM позиционируем курсор повторно COLOR PRINT COLOR V=V+1 NEXT COLOR COLOR Аф=INKEYS:IF A$="" GOTO 4720 LOCATE , POS(0)-1:PRINT AS;:REM печать введенных данных RETURN I REM--2-X строчное меню-- I Vz22 ».Н=5 I N=2 ) ОРТф (1) = " <Д> Добавить. <И> Изменить <У> Удалить •' ( ОРТф(2)=" <Ы> вЫйти из программы •’ f GOSUB 4600 I END 0,7:REM инверсия ОРТ$(А);:REM вывод 7,0:REM нормальное 23, 0:PRINT"-";:REM 7,0: REM нормальное А-ой строки меню отображение мигающий курсор отображение Рис. 6.22. Подпрограмма формирования меню, занимающего часть кадра (строки 4600—4740) 204
ния значений аргументам и вызова подпрограммы. Эти строки порождают меню, изображенное на рис. 6.19. Присвоения производятся в строках 10000— 10050. Меню состоит из двух строк, и эти строки определяются в строках 10040 и 10050 программы. Строка 10060 вызывает подпрограмму построения меню. Все стро¬ ки меню, кроме последней, должны иметь одинаковую длину. Последняя строка должна быть на один символ короче, чтобы в этой позиции разместить мигающий курсор1. Других сложностей в этой программе нет. ПРОСТОЙ ВЫБОР По сравнению с формированием меню программирование про¬ стого выбора представляет собой легкую задачу. Вот несколько примеров подсказок, предлагающих пользователю сделать простой выбор: • Желаете продолжать? (д/н) • Нуждаетесь в указаниях? (д/н) • Вы уверены? (д/н). Такие подсказки появляются, когда пользователь приходит в точку программы, где должно быть принято решение. Простейший способ узнать решение пользователя — выдать на экран не¬ сложный вопрос, на который можно дать только два отве¬ та. Можно спрашивать, печатать ли отчет, стереть ли файл или выполнить ли определенную программу. Сформировать на экра¬ не двухвариантный вопрос намного легче, чем двухвари¬ антное меню. Конечно, ответ на такие вопросы можно получить и с помощью меню. Однако,на мой взгляд, это значило бы палить из пушки по воробьям. Как правило, меню лучше оставить на тот случай, ког¬ да потребуется выбирать по меньшей мере из трех вариантов. Про¬ стой двухвариантный выбор при желании можно использо¬ вать вместо меню. Любую программу, которая может работать с меню, можно переписать так, чтобы в ней содержались только двухвариантные вопросы. Проиллюстрируем это положение. В качестве исходного выберем меню, изо¬ браженное на рис. 6.7. Его можно преобразовать в следую¬ щую последовательность вопросов: Хотите ли вы обновить свои файлы? (д/н) Хотите ли вы провести анализ базы данных? (д/н) Хотите ли вы редактировать базу данных? (д/н) Хотите ли вы привести в порядок свои счета? (д/н) Хотите ли вы завершить работу программы? (д/н) В начале выполнения программы задается первый вопрос. Если пользователь введет букву «д», то начнет выполняться первая 1 Меню выводится в режиме инверсии и благодаря строкам равной длины имеет аккуратный вид.— Примеч. пер. 205
подпрограмма. После того как она отработает, будет повторно задан первый вопрос. Если пользователь ответит «н», ему будет задан второй воп¬ рос. Если он снова ответит «н», ему будет задан третий вопрос и так будет продолжаться до тех пор, пока не будет задан послед¬ ний вопрос. Если пользователь и на него ответит «н», то вопросы возобновятся, начиная с первого. Пока пользователь отвечает «н», вопросы задаются по циклу. Если в программе предусмотрено большое число вариантов работы, то подобный способ управления становится очень неуклю¬ жим и медлительным. Представьте, что ваша программа имеет дюжину различных режимов работы, а вам нужно выполнить вариант номер 11. Если в тот момент, когда, наконец, появится нужный вопрос, вы по инерции случайно нажмете не ту клавишу, то, наверное, такая ситуация вызовет у вас очень сильное раздра¬ жение. Если программа содержит менее, скажем, шести вариантов, то, возможно, она будет неплохо управляться и с помощью простого выбора. Отвечать на вопросы естественнее и во многих отношениях легче, чем работать с меню. Даже если для управления вашей программой простой выбор почти не применяется, с помощью этой техники можно принимать ответы на отдельные вопросы типа приведенных выше. В таких' ситуациях простой выбор просто идеален. Программировать вы¬ дачу подобных подсказок очень просто, поэтому составление соот¬ ветствующих процедур я оставляю читателям. КОМАНДЫ Приходилось ли вам когда-нибудь работать на мини¬ компьютере или большой ЭВМ, где применяется язык команд? Возможно, вы работали с операционной системой UNIX или другой мощной операционной системой, не предоставляющей меню или подсказки с экрана, а требующей ввода специальных сис¬ темных команд, которые необходимо держать в памяти. Языки команд бывают очень мощными. Они дают возможность пользо¬ вателю определять те задачи, которые он желает решать. Поль¬ зователь должен знать, какие команды ему следует набирать, и тогда все возможности машины будут в его распоряжении. Недостаток подобного метода управления работой программы заключается в том, что пользователь должен заранее выучить все команды наизусть. Нет ни удобных меню, помогающих освежить в памяти режимы работы программы; ни страховки, позволяющей исправить ошибки; ни подсказок, ведущих в нужном направлении. Пользователь отвечает за себя сам. Эту цену приходится платить за предоставляемые возможности. Тем не менее специалисты по 206
0 REM Текст программы сети, не использующей меню 1 REM SAVE"A:FIG6-23",А 960 WIDE7.-80 990 GOTO 10000 1300 REM--Очистить одну строку-- 1310 LOCATE V, H:REM переместить курсор в требуемую позицию 1320 PRINT SPACES (WIDE*/.♦ 1-Н) ;: REM стереть все до конца строки 1330 LOCATE V, H:REM вернуть курсор в требуемую позицию 1340 RETURN 1500 REM--Центрирование и вывод заголовка- 1510 Т= (WIDE*Z+ 1 -LEN (Тф)) /2 1520 LOCATE ,TiREM позиционирование курсора по горизонтали 1530 COLOR 0,7:REM инверсия 1540 PRINT Тф 1550 COLOR 7,0:REM нормальное отображение 1560 RETURN 3010 REM--Ввод данных с помощью оператора LINE INPUT-- 3020 GOSUB 1300:REM очистить строку и определить место для подсказки 3030 COLOR 0,7:REM инверсия 3040 PRINT P$+":";:REM вывод подсказки 3050 COLOR 7,0:REM нормальное отображение 3060 LINE INPUT Аф 3070 RETURN 4010 REM--Пауза-- 4020 LOCATE 23, WIDE7./2-23 4030 COLOR 16, 7:REM режим мигающего инвертированного отображения 4040 PRINT"[Для продолжения работы нажмите клавишу пробела]"; 4050 COLOR 7,0:REM режим нормального отображения 4060 Аф=1НКЕУф:1Е А$<>" " GOTO 4060 4070 PRINT 4080 RETURN 10000 REM--Ввод данных-- 11000 REM--Селектор, выполняющий вводимые команды-- 11010 CT.S 1102b ,V=12 11030 Н:30 11040 Рф="НАЗВАНИЕ ПРОГРАММЫ" 11050 GOSPB- 3010 11060 IF Аф="С1" THEN GOSUB 14000 11070 IF Аф="С2" THEN GOSUB 15000 11080 IF Аф'="Р1" THEN GOSUB 17000 11090 IF A$="D2" THEN GOSUB 18000 11100 IF Аф-"El"THEN GOSUB 21000 11110 IF Аф="Е2" THEN GOSUB 22000 11120 IF A^="F1" THEN GOSUB 24000 11130 IF A$="F2" THEN GOSUB 25000 11140 IF Аф-"выйти" OR Аф-"ВЫЙТИ" THEN CLS:END:REM Конец 11150 GOTO 11000 14000 ИЕМ--Кадр С1 — 14010 CLS 14020 Тф="КАДР С1" 14030 GOSUB 1500 14040 GOSUB 4010 14050 RETURN 15000 REM--Кадр С2-- 207
15010 CLS 15020 Т$-"Кадр C2" 15030 GOSUB 1500 15040 GOSUB 4010 15050 RETURN 17000 REM--Кадр D1-- 17010 CLS 17020 Т$="КАДР DI" 17030 GOSUB 1500 17040 GOSUB 4010 17050 RETURN 16000 REM--Кадр D2-- 18010 CLS 18020 Т^-"КАДР D2" 16030 GOSUB 1500 18040 GOSUB 4010 18050 RETURN 21000 REM--Кадр E1-- 21010 CLS 21020 Т$="КАДР El" 21030 GOSUB 1500 21040 GOSUB 4010 21050 RETURN 22000 REM--Кадр E2-- 22010 CLS 22020 Тф="КАДР E2" 22030 GOSUB 1500 22040 GOSUB 4010 22050 RETURN 24000 REM--Кадр F1-- 24010 CLS 24020 Тф="КАДР Fl" 24030 GOSUB 1500 24040 GOSUB 4010 24050 RETURN 25000 REM--Кадр F2-- 25010 CLS 25020 Т^-"КАДР F2" 25030 GOSUB 1500 25040 GOSUB 4010 25050 RETURN Рис. 6.23. Программный текст, позволяющий поль¬ зователю выбирать вариант работы программы не¬ посредственно, без помощи меню ЭВМ предпочитают язык команд языкам, существенно использу¬ ющим выдаваемые на экран подсказки. Не стану советовать вам моделировать язык команд с помощью языка BASIC. Однако довольно легко дать пользователям возмож¬ ность выбирать программы непосредственно, просто вводя их наи¬ менование, возможно, сокращенное. Для иллюстрации этого положения вернемся к изображенному на рис. 6.12 трехуровневому дереву меню. Напомним, что сначала пользователь видит главное меню, выбирает по нему один из ва¬ риантов и переходит к меню уровня 2, по этому меню он переходит на уровень 3, а затем выбирает один из восьми кадров вывода (Cl, С2, DI, D2, El, Е2, F1 или F2). Напомним, что вывод этих кадров может быть заменен на выполнение подпрограмм или дру¬ гие действия. 208
Теперь предположим, что мы исключили все меню из програм¬ мы. Вместо этого будем выдавать на экран такую подсказку: ИМЯ ПРОГРАММЫ: Для выбора кадра пользователь вводит его наименование (С1, С2, D1 и т. п.). Напишем программный текст, принимающий эти данные и присваивающий значение соответствующей переменной, а затем воспользуемся логикой IF—THEN для перехода к затребо¬ ванной части программы. На рис. 6.23 приведена модифицированная версия'изображен¬ ной на рис. 6.13 программы: ранее для управления работой программы применялись меню, а теперь—команды, вводимые пользователем. Для удобства программирования ввод данных осуществляется подпрограммой, использующей оператор LINE INPUT. Текст этой подпрограммы начинается в строке 3010. Подпрограмма формиро¬ вания меню — первая ее строка — 4200— и фрагмент программы, формирующий меню, — первая строка—10000—были удалены. От старой программы остались только подпрограммы формиро¬ вания фиктивных кадров вывода, которые начинаются в строках 14000, 15000, 17000, 18000, 21000, 22000, 24000 и 25000. Новая управляющая часть подпрограммы состоит из строк 11000—11150. В строках 11020—11040 аргументам подпрограммы ввода данных присваиваются значения, соответствующие выдаче подсказки «ИМЯ ПРОГРАММЫ:» в 30-й позиции 12-й строки экрана. Если вы работаете с 40-колонным экраном, замените столбец 30 на столбец 10. Строка 11050 вызывает эту подпрограм¬ му. Строки 11060—11140 проверят с помощью оператора IF— THEN введенные данные и передадут управление на часть про¬ граммы, формирующую требуемый кадр. Для завершения работы пользователь вводит слово «конец» или «КОНЕЦ» (см. строку 11140). Если введенные данные не пройдут ни одной из проверок, то через строку 11150 управление будет возвращено на стро¬ ку 11000, в результате чего подсказка будет выдана повторно и будут введены другие данные. Если пользователь введет допустимые данные, скажем слово С1, то один из операторов IF—THEN вызовет подпрограмму фор¬ мирования соответствующего фиктивного кадра. После выполне¬ ния этой подпрограммы управление будет передано строке, следующей за вызвавшей подпрограмму, что в конце концов при¬ ведет к повторному формированию подсказки. Управление программой с помощью команд в основном нужно для увеличения скорости работы. Очевидно, что запомнить и ввести название функции программы сложнее, чем найти его в меню и на¬ жать клавишу идентификатора варианта. Но если ваша про¬ грамма достаточно велика и содержит много вариантов работы, то на продвижение через многочисленные меню требуется 209
много времени. Возможно, будет быстрее просто набрать название варианта работы. Очевидно, что это можно делать не в любой программе и что такой способ работы удовлетворит не любого пользователя. Описанный способ управления работой программы скорее устроит таких пользователей, которые очень тщательно изучили программу и могут обходиться без меню. КАК СОЧЕТАТЬ МЕНЮ И КОМАНДЫ Имеет ли смысл применять управление с помощью меню и вво¬ димых команд в одной программе? Предположим, например, что главное меню вашей программы выглядит так, как изображено на рис. 6.24. Это меню кажется довольно обычным, но последним из содержащихся в нем ва¬ риантов будет вариант К — команды. Если пользователь нажмет клавишу «К», то меню исчезнет, а вместо этого появится под¬ сказка: ИМЯ ПРОГРАММЫ: Теперь пользователь может набрать имя подпрограммы и вызвать ее так, как это описывалось в предыдущем параграфе. Рис. 6.24. Меню с вариантом управления работой программы — «Команды» (К) 210
Если, напротив, пользователь пожелает вернуться к работе с меню, то для выдачи на экран главного меню ему будет достаточно набрать слово «Меню». Программой можно управлять двумя способами, и пользователь может выбрать любой из них. Но зачем писать такую программу? Преимущество таких программ заключается в том, что пользо¬ ватели могут выбирать один из двух способов управления: рас¬ считанный на новичка и рассчитанный на опытного пользователя. Новичок может вначале пользоваться меню. Поработав с програм¬ мой какое-то время, он превращается в специалиста. Теперь он может обходиться без меню. Короче говоря, программа «растет» с ростом квалификации пользователя. Это очень неплохо. Все же такую возможность целесообразно обеспечивать далеко не в каждой программе. Полагаю, что она может быть полезна только в том случае, если программа сложна, а пользователь работает с ней много времени. Если выполнены оба эти условия, то, вероятно, пользователю будет удобно иметь возможность управлять программой либо посредством меню, либо с помощью вводимых им команд по своему выбору. Не будем далее описывать программирование двойного управ¬ ления: это было бы простыми вариациями на тему только что продемонстрированной методики. Надеюсь, что ваша изобрета¬ тельность, воображение и профессиональные знания помогут решить вам эту задачу самостоятельно.
Глава 7 ОРГАНИЗАЦИЯ ЦЕПОЧЕК ПРОГРАММ Один из методов установления связи между отдельными программами называется организацией цепочек программ. По ме¬ ре роста сложности программ растет и их размер. Однако размер программы, помещающейся в памяти ПК определенного объема, ограничен. Кроме того, чем больше у вас будет перемен¬ ных и чем больше файлов вы загрузите в память, тем меньше места останется для самой программы. В какой-то момент может возникнуть одна из двух ситуаций: либо программа помещается в памяти, но-не остается места для обрабатываемых данных, либо наоборот. Если вы все заранее рассчитаете и обнаружите, что программа совместно с данными не помещается в памяти, то, возможно, вы сочтете нужным или сократить программу, или уменьшить максимальный объем обрабатываемых ею данных. Иными слова- ми^вам придется сузить поставленные задачи. Но если во время работы программы память окажется исчерпанной неожиданно для вас, то ваши планы перечеркнет сама жизнь: об этом вы узнаете, увидев безжизненный экран. В лучшем случае на экране появится сообщение об отсутствии свободной памяти, в худшем — ком¬ пьютер «впадет в прострацию» и больше не будет реагировать на ваши команды. Рассматриваемая проблема имеет решение, не требующее отка¬ за от планировавшихся возможностей программы. Длинные про¬ граммы разбивайте на программы меньшего размера, загружа¬ емые в память поочередно. Тогда у вас останется память для работы. Такая техника программирования широко исполь¬ зуется в экономических приложениях и называется созданием це¬ почки программ. Разбивая одну большую программу на две или несколько меньших по объему, вы разделяете ее на модули гло¬ бального уровня. Есть хорошие и плохие способы разбиения программ на модули, и для того, чтобы получить хорошие модули, недостаточно разре¬ зать распечатку программы ножницами пополам. Поэтому насто¬ ящая глава начнется с обсуждения некоторых типичных способов разбиения программ на модули. Во втором параграфе будут 212
описаны операторы, применяемые при программировании цепочек. Это технические аспекты безопасного перехода от программы А к программе В. Последний параграф посвящен проверке присут¬ ствия программы на диске. При переходе к следующей про¬ грамме цепочки необходимо, чтобы диск, на котором она записана, находился в дисководе: в противном случае первая программа завершит свою работу аварийно. Как убедиться, что программа, к которой мы переходим, действительно находится на дисководе? Об этом пойдет речь в последнем параграфе данной главы. РАЗБИЕНИЕ ПРОГРАММ НА МОДУЛИ Разбиение программ на модули уже обсуждалось в гл. 3, где подчеркивалась важность разработки программ модуль за модулем и доведения каждого из них до совершенства. Затем раз¬ личные модули объединяются в одну программу. Некоторые разработчики предпочитают разбивать свои про¬ граммы на такие модули, которые являются отдельными програм¬ мами. Одно из достоинств такого подхода заключается в том, что проверить и оценить работу модуля легче, если он отделен от остальных частей программы. Вы можете сбросить его копию на диск и отдать для тестирования кому-нибудь другому: это облегчит его проверку. Разработанные подобным способом программы на¬ много легче сопровождать и отлаживать. Если возникает какая-то неполадка, то обычно ее можно локализовать с точностью до конкретного модуля, работающего неправильно. Недостаток этого метода заключается в том, что такие про¬ граммы почти всегда требуют больше места на диске, чем програм¬ мы, разработанные в виде одного большого текста. Во многих программах используются общие подпрограммы, и эти подпро¬ граммы могут составлять до 50% и даже большую часть их текста. При разбиении программы на отдельные модули многие из этих подпрограмм приходится повторять в каждом модуле, занимая под них больше места на диске, чем если бы программа представляла единое целое. (Используя рассматриваемую далее технику перекрытия программ (оверлейную технику), можно су¬ щественно уменьшить подобное дублирование.) Другое преимущество программ, имеющих форму цельного тек¬ ста, — скорость работы. Если ваша программа разбита на отдель¬ ные модули и вам необходимо переходить от модуля А к другому, связанному с ним в цепочку модулю В, она должна загрузить с диска этот новый модуль. На это уходит время. Если вместо перехода по цепочке вы просто передадите управление другой части одной длинной программы, то это займет малую долю секунды. Очевидно, что передача управления происходит 213
намного быстрее, чем загрузка. Программы, состоящие из отдель¬ ных модулей, дают некоторые преимущества разработчику, с точки зрения пользователя, они обладают существенным не¬ достатком — относительно низкой скоростью. Но в данной ситу¬ ации стороны не равны. При прочих равных условиях интересы пользователя намного важнее, чем удобства разработ¬ чика. К сожалению, мы не всегда имеем возможность выби¬ рать. Если вы хотите включить в свою программу некоторые функции и при этом ограничены по объему памяти, то при¬ ходится разбивать программу на модули и соединять их в цепочку. Для того чтобы найти наилучший способ разбиения программы на модули, необходимо проанализировать эту программу. Прежде всего обратите внимание на скорость работы программы. Разби¬ вать программу на модули следует так, чтобы обеспечить наи¬ большую скорость ее работы. Но, выигрывая в одном, прихо¬ дится уступать в другом. Чем больше модуль по объему, тем большая часть программы может в него поместиться и тем быстрее будут выполняться расположенные в нем подпрограммы. Напро¬ тив, чем меньше модуль по объему, тем быстрее он будет за¬ гружаться. Нет никаких жестких и простых правил разбиения программ на модули, но существуют два полезных критерия, которые следует всегда учитывать: частота использования каждой под¬ программы и взаимосвязь между подпрограммами. Чем чаще выполняется некоторая подпрограмма, тем важнее обеспечить к ней быстрый доступ. Поэтому подпрограммы, к которым поль¬ зователь обращается чаще всего, целесообразно объединять в один модуль, если только это возможно. Если, скажем, между подпрограммами ввода данных и редактирования базы данных имеется взаимосвязь, то объедините их в один модуль, чтобы пользователь мог быстро переходить от одной подпрограммы к другой. Проиллюстрируем применение этих критериев к реальным зада¬ чам. Представьте, что вам доступно 60 Кбайт памяти ПК и что вы занимаетесь предварительным проектированием двух различ¬ ных программ. Каждая из этих программ должна включать пять подпрограмм. Вы провели анализ и определили требуемый для каждой из подпрограмм объем памяти, вероятную частоту их использования и взаимосвязь между подпрограммами. Результаты анализа приведены в табл. 7.1 (для программы 1) и 7.2 (для программы 2). Рассмотрим программу 1. Один из способов разбиения ее на модули изображен на рис. 7.1. Подпрограммы 1, 2 и 5 объединены в один общий модуль, так как подпрограммы 1 и 2 часто исполь¬ зуются и имеется взаимосвязь между подпрограммами 2 и 5. Под¬ программа 3 и подпрограмма 4 занимают большой объем памяти, 214
ПАМЯТЬ, ЧАСТОТА ПОДПРОГРАММА Кбайт ИСПОЛЬЗОВАНИЯ ЗАВИСИМОСТЬ 1 15 высокая 2 13 высокая 5 3 42 низкая - 4 44 средняя — 5 19 низкая 2 Табл. 7.1. Результаты анализа программы 1 ПОДПРОГРАММА ПАМЯТЬ, Кбайт ЧАСТОТА ИСПОЛЬЗОВАНИЯ ЗАВИСИМОСТЬ 1 42 высокая - 2 41 низкая - 3 45 низкая — 4 44 средняя - 5 49 низкая - Табл. 7.2. Результаты анализа программы 2 поэтому они размещены в отдельных модулях. Итак, основная часть программы состоит из трех модулей, каждый из которых связан с двумя другими и может вызвать любой из них. Это означает, что копия главного меню (или другого механизма управления программой) должна содержаться в каждом из моду¬ лей. Кроме того, в программе имеется четвертый модуль (модуль инициализации), связанный только с модулем, содержащим под- Рис. 7.1. Один из способов разбиения программы 1 на модули 215
программы 1, 2 и 5. Выделение такого модуля не обязательно, но в программах, разбитых на модули, он часто бывает удобен, а иногда даже и необходим. Программа начинает свою работу с выполнения этого модуля, который выделяет память под массивы и делает прочую работу по инициализации. Если соответствующие операторы оформить в виде отдельного модуля, то после того, как они отработают, их будет легко удалить и, следовательно, они не будут перегружать основную часть программы. Кроме того, если эти операторы хранятся отдельно, то проще избежать некоторых ошибок типа попыток изменить размер масси¬ ва. Рассмотрим теперь программу 2. Табл. 7.2 показывает, что по распределению памяти, частоте использования и взаимосвязям подпрограммы программы 2 существенно отличаются от подпро¬ грамм программы 1. Более всего они разнятся требованиями к памяти. Подпрограммы программы 2 настолько велики, что никакую их пару объединить невозможно. Каждая подпрограмма должна образовывать отдельный модуль. В результате полу¬ чается проект программы, изображенный на рис. 7.2. Рис. 7.2. Один из способов разбиения программы 2 на модули В этом проекте модуль меню будет центральным. Он загружа¬ ется в начале работы (модулем инициализации). Из модуля меню пользователь имеет, доступ к любому другому модулю. Закончив работу с очередным модулем, пользователь возвращается в модуль меню. Затем выполняется следующая подпрограмма и т. д. 216
В этих примерах представлены два типичных случая органи¬ зации цепочек подпрограмм. Конечно, программа 2 иллюстрирует ситуацию, наиболее неудачную для построения цепочки про¬ грамм. В программе 1 несколько подпрограмм объединяются в небольшое число модулей. В обоих проектах есть модуль инициализации, выделение которого не обязательно, но, как пра¬ вило, желательно. Другое существенное отличие между програм¬ мами состоит в расположении главного меню. В программе 1 оно продублировано в каждом модуле и каждый модуль свя¬ зан со всеми остальными. В программе 2 главное меню образует отдельный модуль, и только он связан со всеми остальными модулями. Если все или некоторые из ваших подпрограмм содержат общие фрагменты программного текста, то возможно применение техники перекрытия (организации оверлейных структур), суть ко¬ торой заключается в том, что некоторые части программы дер¬ жатся в памяти постоянно, тогда как другие вводятся и удаляются из нее по мере надобности. Например, в памяти могут постоянно находиться подпрограммы, образующие ядро програм¬ мы, а управляющие («разумные») ее части могут считываться тогда, когда это необходимо. Рис. 7.3. Организации цепочки программ с перекрытием (оверлеем) 217
Техника перекрытия проиллюстрирована рис. 7.3. В этом при¬ мере подпрограммы ядра, состоящие из строк с номерами от О до 9999, остаются в памяти все время, а управляющие части пяти подпрограмм, содержащиеся в строках с номерами 10000 и выше, вводятся и выбрасываются из памяти. Преи¬ мущество перекрытия заключается в том, что оно уменьшает размер подпрограмм, экономит место на диске и сокращает время вызова подпрограмм. Разбиение программы на модули, изображенное на рис. 7.2, требует использования техники перекрытия, если, конечно, в различных ее модулях содержится общий текст, например общие подпрограммы или меню. Общий модуль должен включать этот общий текст. Для выделения текста, общего для нескольких модулей, необходимо проанали¬ зировать программу. Ясно, что для ускорения доступа к главному меню, к которому может обратиться любая подпрограмма, оно должно все время находиться в памяти. Эти примеры, при всей их простоте, показывают, какого рода анализ следует проводить при разбиении программ на модули. Проведя этот анализ и приняв решение о составе модулей, вам следует связать их между собой и написать операторы, создающие цепочки программ. В следующем параграфе сообща¬ ется, как это делать. КАК СОЗДАВАТЬ ЦЕПОЧКИ ПРОГРАММ Язык BASIC для ПК дает возможность очень легко созда¬ вать цепочки, по которым можно переходить от одной программы к другой. Для этого используется оператор CHAIN. Введите в ПК следующую программу: 10 REM— Программа А — 20 CLS 30 PRINT ’’Программа А” 40 CHAIN ’’PROGB” и сбросьте ее на диск под именем «PROGA. BAS», а потом введите вторую программу и сохраните ее на диске под именем «PROGB. ^AS»: 10 REM — Программа В — 20 CLS 30 PRINT”nporpaMMa В” Теперь запустите программу PROGA.BAS и посмотрите, что произойдет. PROGA должна вызвать PROGB, и на экране должно появиться сообщение «Программа В». В этом и состоит суть создания цепочек программ. Дело ос¬ ложняют некоторые моменты. Прежде всего если вы просто перей- 218
0 REM Рис. 7-4 4 REM SAVE"A:PROGA, BAS",A 210 C1Z=10 220 C2 = .5 230 C3#-333333432674408# 240 "чеканные строки" 250 WIDEZ=80 990 GOTO 10000 4010 REM--Пауза-- 4020 LOCATE 23, WIDEZ/2-23 4030 COLOR 16, 7:REM режим мигающего инвертированного отображения 4040 PRINT"[Для продолжения работы нажмите клавишу пробела]"; 4050 COLOR 7,0:REM режим нормального отображения 4060 A$=INKEY$:IF А|<>" " GOTO 4060 4070 PRINT 4060 RETURN 10000 REM--Сообщаем название программы и выводим данные*-- 10010 CLS 10020 PRINT"Программа А" 10030 LOCATE 10 10040 PRINT "С17. = ";С17. 10050 PRINT "С2=";С2 10060 PRINT "C3#z";C3# 10070 PRINT"C$" ’, С| 10080 PRINT"WIDEZ=";WIDE/ 10090 GOSUB 4010 10100 REM--Переходим по цепочке к Программе В-- 10110 CHAIN"PROGB" Рис. 7.4. Программа А 0 REM Рис. 7-5 1 REM SAVE"A:PROGB. BAS" , А 10000 REM--Сообщаем название программы и выводим данные-- 10010 CLS 10020 PRINT"Программа В" 10030 LOCATE 10 10040 PRINT "C1Z. = "; C1Z 10050 PRINT "C2-";C2 10060 PRINT "C3#=";C3# 10070 PRINT"C$=";C$ 10080 PRINT"WIDEZ = "; WIDE/. Рис. 7.5. Программа В дете из программы А в программу В по цепочке, то будут утеряны значения всех численных и строковых переменных. В качестве примера рассмотрим простую демонстрационную программу. На рис. 7.4 изображен более серьезный вариант программы PRGGA, но и этот вариант очень прост. В строках 210—250 пяти переменным — Cl%, С2, СЗ#, С$ и WIDE% — присваиваются значения. Строки 4010—4080 содержат знакомую нам подпрограмму паузы, приостанавливающую работу програм¬ мы до нажатия клавиши пробела. Строки 10000—10080 выдают на экран присвоенные этим пяти переменным значения. Строка 10090 вызывает подпрограмму паузы, а строка 10110 вызывает по цепочке программу PROGB 219
Потратьте несколько минут на ввод этой программы в ПК и сбросьте ее на диск под именем «PROGA». В дальнейшем мы создадим несколько вариантов этой программы, иллюстриру¬ ющих различные аспекты вызова по цепочке. Сбросив PROGA на диск, превратим ее в программу PROGB, убрав строки 0—4800 и 10090—ЮНО и добавив новые строки 0, 1 и 10020 (рис. 7.5). Поместив обе программы на одном диске, запустите PROGA и посмотрите, что из этого получится. Программа. PROGA должна очистить экран, выдать на него присвоенные переменным зна¬ чения и ждать, пока вы не нажмете клавишу пробела. Затем PROGA вызовет по цепочке программу PROGB. При выполнении последней программы выводимые значения переменных должны отличаться от тех, которые были им присвоены в программе PROGA: в PROGB все численные переменные будут иметь нулевое значение, а С$ превратится в пустую строку. ПЕРЕДАЧА ПЕРЕМЕННЫХ ПРИ ПЕРЕХОДЕ ПО ЦЕПОЧКЕ В некоторых случаях потеря присвоенных переменным зна¬ чений не создает никаких затруднений, но в большинстве программ при переходе по цепочке желательно сохранить зна¬ чения по крайней мере некоторых переменных, а возможно, и всех. Это можно сделать двумя способами, и оба они довольно просты. При первом способе используется оператор COMMON, а при втором — параметр ALL оператора CHAIN. Рассмотрим вначале оператор COMMON. Этот оператор поз¬ воляет определить переменные, которые следует переносить при переходе по цепочке из одной программы в другую. Оператор COMMON имеет следующий формат: COMMON переменная 1, переменная 2, ... Чтобы, например, передать из программы PROGA в программу PROGB численные переменные С1% и С2, в текст PROGA следует вставить такой оператор: COMMON Cl%, С2 Этот оператор может располагаться в любом месте программы, но он должен выполняться раньше оператора CHAIN. Для иллюстрации того, как работает оператор COMMON, загрузите программу PROGA и вставьте в нее следующую строку: 10105 COMMON С1 %, С2 Сбросьте модифицированную версию PROGA на диск под именем PROGA1. Запустите эту программу и посмотрите, что произойдет при выполнении PROGB. Значения переменных С1% и С2 должны быть перенесены в PROGB без изменений, но значения всех остальных переменных должны быть утеряны. 220
Теперь продемонстрируем работу параметра ALL. Этот па¬ раметр вызывает передачу из первой программы во вторую всех переменных. Он следует за оператором CHAIN. Это третий из параметров данного оператора, а первый из них — имя файла. Поэтому от имени файла параметр ALL должны отделять две запятые. Чтобы, например, передать из программы А в программу В все переменные, замените строку 10110 программы А на следую¬ щую: 10110 CHAIN ’’PROGB”, ALL Внесите это изменение в PROGA и сохраните получившуюся программу под именем «PROGA2». Затем запустите эту програм¬ му. Все переменные должны перенестись в PROGB без изменений. Очевидно, что параметром ALL пользоваться намного легче, чем оператором COMMON. Но бывают случаи, когда нежела¬ тельно передавать из первой программы во вторую все перемен¬ ные. На самом деле следует передавать только глобальные переменные, т. е. переменные, которые используются во всей программе. Передавать локальные переменные, не несущие полез¬ ной информации, не имеет смысла. Оператор COMMON позволяет передавать из одной программы в другую только нужные пере¬ менные. ПЕРЕКРЫТИЕ ПРОГРАММ (ОВЕРЛЕИ) При переходе по цепочке во время загрузки нового модуля можно сохранить в памяти и старый модуль — целиком или частично. Для этого к оператору CHAIN следует добавить три дополнительных параметра: слово MERGE, номер строки, с кото¬ рой должно начаться выполнение загружаемой программы, и слово DELETE с указанием диапазона удаляемых строк старой программы. Оператор CHAIN с дополнительными параметрами имеет следующий синтаксис: CHAIN MERGE ”имя-файла”, начальная-строка,ALL,DELETE диапазон-строк Для того чтобы, например, перейти по цепочке к программе С, начать ее выполнение со строки 10000, передать в нее все пере¬ менные и сохранить строки 0—9999 программы А, воспользуйтесь таким оператором: 10110 CHAIN MERGE’’PROGB”,10000,ALL.DELETE 10000—10110 Вставьте эту строку в программу А и сбросьте получившуюся программу на диск под именем «PROGA3>>. Теперь загрузите PROGB и преобразуйте ее в программу PROGC, добавив такую строку: 10090 GOSUB 4010 221
Строка 10090 обращается к строке 4010, отсутствующей в програм¬ ме С; эта строка будет передана в нее из программы А. Запустите программу АЗ и посмотрите, что за этим последует. Переменные должны передаться из программы в программу без изменений, а вызов подпрограммы не должен вызывать сообщения об ошибке. Выведите командой LIST текст программы PROGC на экран и убедитесь, что в нее была передана подпрограмма. Этот пример иллюстрирует суть техники перекрытий. В данном случае передавалась только одна простая подпрограмма, но ту же методику можно использовать в сложных программах, имеющих большой объем, в которых из одной программы в другую пере¬ даются сотни строк программного текста. Мы изложили основные положения по использованию операто¬ ра CHAIN, но разобрали его далеко не полностью. Дополни¬ тельная информация содержится в руководстве по языку BASIC. ПРОВЕРКА ПРИСУТСТВИЯ ПРОГРАММ НА ДИСКЕ Переход от программы к программе по цепочке может пройти нормально только в том случае, если в момент перехода диск с вызываемой программой находится в дисководе. В противном слу¬ чае происходит ошибка обращения к диску, и программа пре¬ кращает работу. Если все ваши программы находятся на одном диске, который никогда не вынимается из дисковода, то с этой пробле¬ мой вы не столкнетесь. Но если программа требует смены дисков (swapping), то могут возникнуть некоторые сложности. (Сменой дисков, или «свапом», называют деятельность, при которой диск вставляют на время в дисковод, вынимают его обратно, вставляют другой диск, заменяют его опять на первый и т. д.) Сменять диски приходится в тех случаях, когда не все требуемые программой файлы находятся на одном диске. Например, ваша программа может быть настолько велика, что она просто не помещается на одном диске. Но даже если ваша программа и не должна была бы требовать смены дисков, ее следует защитить от ошибочных действий пользователя. Когда придет время переходить по цепоч¬ ке, он может случайно вставить в дисковод не тот диск. К счастью, предотвратить аварийное завершение работы прог¬ раммы по такой причине очень легко. Можно просто поместить в программу оператор ON ERROR GOTO и подпрограмму обработки ошибок. При выполнении оператора CHAIN интерпретатор языка BASIC ищет на диске файл с программой, к которой следует перейти по цепочке. Если она присутствует на диске, то происхо¬ дит переход. В противном случае интерпретатор идентифицирует ошибочную ситуацию и сохраняет первую программу в памяти. Другими словами, ваша программа никогда не теряется в «суме¬ 222
речной зоне» между программой А и программой В. Это важное достоинство BASICa ПК фирмы IBM: интерпретаторы языка BASIC многих других микрокомпьютеров не столь «снисходитель¬ ны». Поскольку не тот диск, вставленный в дисковод, — это всегда ошибка человека, причем одна из наиболее часто встречающихся, весьма вероятно, что вы пожелаете обрабатывать ее особым об¬ разом. Под особой обработкой понимается следующее: программа анализирует код ошибки, а встретив именно данную ошибку, вы¬ дает специальное сообщение и обеспечивает соответствующие дан¬ ной ошибке действия по восстановлению работы программы. В данном случае ошибка имеет номер 53 и формулируется так: «file not found in line number X» («в строке номер X не найден файл»). Подробно эта тема разбиралась в гл. 3 (см. процедуры, изображенные на рис. 3.12 и 3.14).
Глава 8 РАБОТА С ФАЙЛАМИ В данной главе речь пойдет о файлах на дисках. Основное внима-ние в ней будет уделено файлам данных. Программисты хранят в таких файлах введенные пользователем данные; они должны знать, как правильно, эффективно и с минимальными осложнениями работать с этими файлами. Работа с файлами не сводится к умению создавать файлы, записывать в них данные и считывать файлы в память. Эти дейст¬ вия образуют ядро любой процедуры ввода-вывода, и програм¬ мисту следует ими владеть. Однако для правильной (т. е. эффек¬ тивной и надежной) работы с файлами одного этого недостаточно. Кроме того, программисту надо уметь планировать файлы, обраба¬ тывать ошибки, напоминать пользователю о необходимости смены дисков и проектировать структуру управления вводом-выводом. Все эти вопросы рассматриваются в данной главе. Если вам достаточно часто приходится программировать ввод- вывод, то вы приобретаете определенную квалификацию в состав¬ лении процедур чтения и записи файлов, смены дисков т. п. В про¬ тивном случае, как обычно, знания постепенно утрачиваются. Ко¬ дировать ввод-вывод файлов довольно сложно, поэтому при рабо¬ те с файлами особенно важно применять подпрограммы. Имея в своей библиотеке хороший комплект подпрограмм ввода-вывода, вы можете брать их и приспосабливать к новым приложениям. В работе с файлами есть еще один аспект. Если вы когда- нибудь переводили программы с одного диалекта языка BASIC на другой, например с BASICa для машины «Apple II» на BASIC для ПК фирмы IBM, то вы знаете, что это за работа. Ее сложность во многом определяется тем, как первоначально была спроектиро¬ вана программа. Если она была построена из подпрограмм, то перевод будет намного легче. Причину этого нетрудно понять. Та часть текста такой программы, которая управляет ее работой, в основном будет состоять из операторов присвоения значений аргументам и вызова подпрограмм. Эти операторы в различных версиях языка BASIC довольно похожи. Скажем, GOSUB 3000 означает практически одно и то же в любом диалекте BASICa. 224
Короче говоря, использование подпрограмм облегчает перевод программ с одной ЭВМ на другую. Вам следует хорошо ознакомиться с основами работы с файла¬ ми как последовательного, так и произвольного доступа. Если вы только начинаете программировать или в последнее время мало этим занимались, то перед тем, как продолжить чтение этой книги, просмотрите следующие разделы руководства по языку BASIC для ПК фирмы IBM. • Приложение В, посвященное вводу-выводу с диска. • Обсуждение необязательных параметров команды BASIC (гл. 2). • Определение следующих операторов и функций языка BASIC: OPEN, CLOSE, WRITE#, INPUT#, FIELD, GET, PUT, LSET, RSET, MKI$, MKS$,MKD$, CVI, CVS и SVD. В данной главе рассматриваются не все операторы работы с файлами, а только наиболее часто используемые. BASIC для ПК — богатый язык, и он часто позволяет программисту выпол¬ нять одну и ту же работу разными способами. Поскольку одна из целей данной книги — дать читателю простые инструменты для работы, изложение не будет исчерпывающим, напротив, как прави¬ ло, будет освещаться только один, но действенный способ реше¬ ния задачи. Если вы сочтете, что представленные здесь методы и приемы недостаточны для решения ваших задач, то обратитесь к документации фирмы IBM. В главе обсуждается несколько тем. Вначале рассматривается планирование файлов. В двух следующих параграфах речь пойдет соответственно о последовательных файлах и файлах с произволь¬ ным доступом. В этих параграфах описываются необязательные параметры команд языка BASIC, ключевые операторы работы с файлами, методы проектирования подпрограмм записи и чтения файлов, а также документирование файлов. Последний параграф посвящен вопросам эффективности и безопасности записи и чте¬ ния файлов. ПЛАНИРОВАНИЕ ФАЙЛОВ Перед тем как начать писать текст программы, очень важно тщательно спланировать файлы. Если вы не выполните эту работу как следует, то, наверное, через некоторое время обнаружите, что занимаетесь изменениями их структуры, добавляя одни и уда¬ ляя другие файлы, или что вы вообще запутались. Фрагменты, которые записывают и читают файлы, должны быть подготов¬ лены на ранней стадии разработки программы. Эта работа в зна¬ чительной степени основывается на некоторых предварительных представлениях о структуре файлов. Следовательно, изменение этих представлений вызовет изменения во всей программе и 8 Зак. 1488 225
приведет к нежелательным последствиям в отношении сроков вы¬ полнения, трудоемкости и качества проекта. Планируйте файлы тщательно и заблаговременно. СОПОСТАВЛЕНИЕ ФАЙЛОВ ПОСЛЕДОВАТЕЛЬНОГО И ПРОИЗВОЛЬНОГО ДОСТУПА Существуют два вида файлов: с последовательным доступом (последовательные файлы) и произвольным доступом. Последо¬ вательный файл содержит одну запись и загружается в память или записывается на диск за одно обращение1. Последовательные файлы часто используют для хранения массивов. Но последо¬ вательный файл может состоять даже из одного-единственного символа, и иногда такие файлы бывают действительно нужны и удобны. Основной характеристикой последовательного файла является не его объем или содержание, а то, что он полностью обрабатывается за одно обращение. Программа считывает содер¬ жимое такого файла за одно обращение. Новые данные она записывает в него также за одно обращение. Последовательные файлы удобны для хранения оглавлений, указателей и прочей информации, которую в той или иной степени можно рассматри¬ вать как единственную в своем роде. Но если ваша программа должна иметь дело с несколькими наборами однотипных данных, то лучше использовать файлы произвольного доступа. Файл произвольного доступа1 2 подобен колоде карт. Он состоит из записей, каждая запись снабжена своим уникальным номером. Можно прочесть или записать одну запись и при этом нет необ¬ ходимости читать или записывать весь файл. Файлы с произволь¬ ным доступом нужны в тех случаях, когда программа должна иметь дело с несколькими различными наборами данных, запи¬ санными в идентичном формате, например личными делами, исто¬ рией динамики цен на акции или анализом рыночных характе¬ ристик недвижимости. 1 Это утверждение неверно. Последовательный файл может состоять (и часто состоит) из многих записей; читать его также можно по частям. После того как последовательный файл будет открыт, для ввода-вывода будет доступна первая запись; каждая последующая команда вводит (выводит) в память (из памяти) очередную запись. Кроме того, файл можно открыть для записи в конец; тогда записи будут добавляться, а не затирать существующие. Последовательный метод доступа имеет следующие недостатки: 1. Для чтения нужной записи приходится вводить все предшествующие ей записи. Если, например, вам нужна 1000-я запись, то вам придется прочесть 999 ненужных. Если после этого вам понадобится запись № 800, то вам придется предварительно закрыть файл, открыть его повторно и прочесть 799 не интересующих вас записей. 2. Не существует способа обновить(изменить) какую-либо запись последовательного файла (кроме, возможно, последней). При изменении хотя бы одного байта приходится со¬ здавать новую версию всего файла.— Примеч. пер. 2 Произвольный доступ называют также прямым доступом; ранее употреблял¬ ся термин «случайный доступ».—Примеч. пер. 226
КАК ОТКРЫВАТЬ И ЗАКРЫВАТЬ ФАЙЛЫ Язык BASIC допускает, что одновременно открытыми могут быть до 15 файлов. Для того чтобы открытыми одновременно были более трех файлов, при загрузке интерпретатора в команде BASIC или BASICA следует задать параметр /F: число-файлов. Этот параметр будет описан в данной главе. Каждый файл занимает 188 байт в блоке управления файлами, а также требует как минимум 128 байт для буфера файла. Если не задать параметр /F:, то интерпретатор BASIC (или BASICA) разрешит открыть три файла. Параметры команды BASIC лучше всего устанавливать с помощью пакетных файлов, описанных в гл. 3. Тогда пользова¬ телю не надо будет набирать эти параметры с клавиатуры вместе с командой BASIC, и не произойдут те неприятности, которые случаются при выполнении программ, если пользователь забывает задать параметры. Как правило, чем меньше файлов открыто в каждый момент, тем лучше, в частности, потому, что каждый открытый файл занимает часть оперативной памяти. Если в вашей программе используется 10 различных файлов, то вам следует решить, дейст¬ вительно ли необходимо, чтобы все они одновременно были откры¬ тыми. Определите минимальное число одновременно открытых файлов, обеспечивающее эффективную работу вашей программы. Если это число меньше 10, то, присвоив параметру /F: команды BASIC соответствующее значение, вы сэкономите немного памяти. Следует иметь в виду, что в программе может использоваться сколько угодно файлов и что все они могут иметь один и тот же номер. Единственное ограничение состоит в следующем: файлы с одним и тем же номером не могут быть одновременно открытыми. Когда вы будете читать эту главу, обратите внимание, что все приведенные в ней подпрограммы чтения и записи содержат опера¬ торы, которые открывают и закрывают файлы. Язык BASIC этого не требует. Можно, например, открыть файл в начале программы, а затем заняться другими делами и не закрывать его до конца работы. Но при выполнении оператора CLOSE на диск записы¬ ваются данные из буфера файла. Частично запись данных про¬ исходит и ранее, но при закрытии файла запись данных на диск завершается правильно. Пока файл не закрыт, существует опасность, что прекраще¬ ние работы программы — из-за ошибки пользователя, отключения электроэнергии или ошибки в программе — приведет к утрате, дан¬ ных или даже к повреждению диска. Опыт показывает, что жела¬ тельно закрывать файл, как только исчезнет необходимость в том, чтобы он был открыт. Очевидно, что когда вы работаете с фай¬ лом, он должен быть открыт. Но неясно, зачем файлу быть откры¬ тым в других случаях, особенно если учесть, насколько важно не утерять данные пользователя. 8* 227
Существуют программы, требующие держать файлы открыты¬ ми в течение более или менее продолжительного времени. Если вам надо написать такую программу, то измените приведенные в дан¬ ной главе подпрограммы записи и чтения файлов, удалив из них оператор CLOSE. При этом подпрограммы перестанут закрывать файлы автоматически, и вам придется их закрывать в управляю¬ щей части программы. ДОКУМЕНТАЦИЯ НА ФАЙЛ Определив, какого рода файлы вам понадобятся, расплани¬ руйте их на бумаге. Составлять подпрограммы чтения или записи файлов нетрудно, но при этом приходится учитывать множество деталей. Учесть эти детали следует заранее, а не тогда, когда вы приступите к вводу текста подпрограммы в компьютер. Подго¬ товка самого текста подпрограммы должна выполняться по воз¬ можности механически. Кроме того, вы должны иметь возможность строить процедуры ввода-вывода в основном из стандартных блоков. Сочинение программы отличается от сочинения романов. Здесь внезапное озарение скорее опасно, чем благотворно. Привычка работать систематически, шаг за шагом, приведет вас к желаемой цели быстрее и с меньшим числом ошибок, чем муза программирования. Чем больше переменных хранится в файлах, тем более важно правильно спланировать файлы. Если в файле хранится всего не¬ сколько переменных, то требования к дисковой памяти будут-не¬ велики, и выбор формата записи не очень существен. Но если в файле хранятся большие объемы данных, то значение планиро¬ вания намного возрастает. В особенности это относится к файлам произвольного доступа, поскольку, не спланировав заранее каж¬ дую запись, невозможно написать хорошую программу обработки такого файла. Планировать файлы можно по-разному. Лучше всего сразу их документировать; тогда само описание файла и будет той его схемой, которая используется при составлении программы. Доку¬ ментировать файлы можно многими способами. Простейший и наиболее популярный способ документации основан на примене¬ нии бланка описания файла, см. табл. 8.1. В таком документе указывается длина записи, ее поля и соответствующие им пере¬ менные программы. В некоторых случаях вполне достаточно иметь такую документацию, но она далеко не полна и мало помогает программисту в кодировании ввода-вывода или разборе уже напи¬ санного текста. Однако документация на файлы предназначена именно для облегчения этих двух задач. Поэтому в документации должны присутствовать некоторые дополнительные сведения, не¬ обходимые программисту. Приведем часть из них. 228
ДОКУМЕНТАЦИЯ НА ФАЙЛ ОПИСАНИЕ ПОЛЯ Наименования Цены МАССИВ/ПЕРЕМЕННАЯ А$(А) А (А) ДЛИНА 24 8 Количество К4% Табл. 8.1. Простой формат документации на файлы. Содержит недостаточно информации • Тип файла: файл последовательного или произвольного доступа. • Имя файла. • Флажки, используемые с этим файлом, например флажок, с помощью которого помечают, записывать ли файл на диск. • Номер файла. • Номера строк, в которых начинаются подпрограммы записи или чтения файла (если процедуры ввода-вывода органи¬ зованы в виде подпрограмм). • Описания полей записи и массивов или переменных, соот¬ ветствующих этим полям: длина полей, число элементов массивов и размер записи (в байтах). • Переменная, содержащая номер записи, например R%; длина записи; число записей и переменные, используемые в операторе FIELD — в случае файла произвольного доступа. Рекомендуемый формат документации на последовательные файлы изображен в табл. 8.2, а формат документации на файлы произвольного доступа изображен в табл. 8.3. В следующем па¬ раграфе данной главы детально описывается, как заполнять такие бланки на последовательные файлы, а в параграфе, следующем через один,— на файлы произвольного доступа. Файлы следует сначала документировать, а затем уже кодиро¬ вать их чтение и запись. Короче говоря, документирование файла является и его планированием. Для того чтобы подгото¬ вить подобную документацию, вам следует хорошо понимать устройство последовательных файлов и файлов произвольного доступа. Этим вопросам будут посвящены два следующих па¬ раграфа. 229
ДОКУМЕНТАЦИЯ НА ФАЙЛ Тип файла: последовательный Наименование файла: NAME. SEQ Флажок: F% Номер файла: Г Запись файла: строка 6000 Чтение файла: строка 6250 СОДЕРЖАНИЕ ФАЙЛА ОПИСАНИЕ ПОЛЯ Наименования Цены МАССИВ/ ПЕРЕМЕННАЯ А$ (А) А (А) МАКС. АРГУМЕНТ 64 64 ДЛИНА 24 8 ЧИСЛО БАЙТ 1536 512 Количество К4% 1 6 6 Табл. 8.2. Рекомендуемый формат документации на последовательные файлы ДОКУМЕНТАЦИЯ НА ФАЙЛ Типа файла: произвольного доступа Наименование файла: NAME. RND Флажок: F% Номер файла: 1 Запись файла : строка 6000 Чтение файла: строка 6250 Число записей: 999 Аргумент записи: R% СОДЕРЖАНИЕ ФАЙЛА МАССИВ/ МАССИВ/ МАКС. ЧИСЛО ОПИСАНИЕ ПОЛЯ ПЕРЕМЕННАЯ ПЕРЕМЕННАЯ АРГУМЕНТ ДЛИНА БАЙТ Наименования А$ (1 -5) F0$ (1-5) 5 24 120 Цены А (1-5), F1$ (1-5) 5 4 20 Количество К4% F9$ 1 2 2 Длина записи = 252 Табл. 8.3. Рекомендуемый формат документации на файлы произвольного доступа 230
ПОСЛЕДОВАТЕЛЬНЫЕ ФАЙЛЫ В данном параграфе рассматриваются параметры команды вызова интерпретатора BASIC (BASICA), относящиеся к после¬ довательным файлам, кодирование ввода-вывода последователь¬ ных файлов (с текстами подпрограмм) и документация на такие файлы. ПАРАМЕТРЫ КОМАНД BASIC И BASICA Для загрузки выполнения программы на BASICe предвари¬ тельно следует загрузить интерпретатор этого языка. Команду BASIC операционной системы можно либо набрать на клавиатуре, либо выполнить в составе пакетного файла. Если за командой BASIC следует имя файла, то после загрузки интерпретатор будет выполнять программу, записанную в этом файле. Если, например, набрать на клавиатуре команду DOS: BASIC OH!SO!.BAS то после загрузки интерпретатора начинается выполнение на¬ писанной на языке BASIC програмы OH!SO!.BAS. Команда BASIC имеет несколько необязательных парамет¬ ров, причем при работе с последовательными файлами имеет значение один параметр, а при работе с файлами произвольного доступа — два. Параметр /F: число-файлов устанавливает макси¬ мальное число файлов, которые могут быть открытыми одновре¬ менно; он используется при работе как с последовательными файлами, так и с файлами произвольного доступа. Если вы не задали этот параметр, интерпретатор BASICa позволит, чтобы открытыми одновременно были максимум три файла. Если в вашей программе столько открытых файлов иметь не нужно, то желатель¬ но сообщить об этом интерпретатору BASICa с тем, чтобы он уменьшил объем памяти, выделяемой под буфера и блок управ¬ ления файлами. Если вам надо одновременно работать более чем с тремя файлами, то задавать соответствующие значения параметра /F необходимо; в противном случае произойдет аварий¬ ное прекращение работы программы. Параметр числа файлов записывается после команды BASIC. Например, для установки числа файлов в программе OH1SO1.BAS равным пяти, дается следующая команда: BASIC OH’SOI.BAS /F:5. Задаваемый так параметр указывает число всех открываемых файлов, как последовательных, так и произвольного доступа. Зафиксированное значение параметра /F, будь то величина, определенная в команде вызова интерпретатора, или принятое по умолчанию значение (три), фиксирует номера файлов, которые можно использовать в программе. Номер файла не может пре¬ вышать значения параметра /F, и файлы с одинаковыми номе¬ 231
рами не могут одновременно быть открытыми. Если, скажем, пара¬ метр /F установлен равным двум, то все файлы программы могут иметь номера 1 и 2, и в каждый момент времени может быть открыт только один файл с номером 1 и один файл с номером 2. В программах на BASICe число различных файлов с одинаковы¬ ми номерами не ограничено, но ограничено число файлов, откры¬ тых в каждый момент. Итак, в различные моменты времени в программе под одним номером могут обрабатываться разные файлы, но при условии, что один из них закрывается раньше, чем открывается другой. ПОДПРОГРАММЫ ЗАПИСИ И ЧТЕНИЯ При составлении подпрограмм записи и чтения последователь¬ ных файлов мы следовали следующим соглашениям. • Подпрограммы обработки файлов помещаются в строках программы с номерами 6000—8999. • Подпрограмма записи предшествует подпрограмме чтения. • Между подпрограммами записи и чтения существует интер¬ вал в нумерации строк, равный примерно 250 строкам. В этих правилах нет ничего особенного, но они помогают не запутаться. Запись файла. Читать можно только уже существующий по¬ следовательный файл, а создается он в тот момент, когда в него' в первый раз записываются данные. Итак, чтобы с таким файлом можно было работать, в него прежде надо что-нибудь записать. Для записи данных в последовательный файл программа долж¬ на выполнить три дёйствия: открыть файл, переслать в него данные и закрыть его. Файл открывается с помощью оператора откры¬ тия файла. Существуют два различных оператора, выполняющих эту работу, но удобнее выучить и пользоваться только одним из них. Простейший оператор открытия последовательного файла имеет следующий синтаксис: OPEN ”d: имя-файла” FOR OUTPUT AS^n Этот оператор имеет следующие параметры: • d — имя дисковода (А или В)1. Если этот параметр будет опущен, то файл будет записан на дисководе, определен¬ ном по умолчанию; • имя-файла — имя файла. Оно может содержать до восьми знаков, а также трехсимвольное расширение; • п — номер файла. Число между 1 и 15, не превышающее значение параметра /Е: команды BASIC (или не превы¬ шающее 3, если этот параметр не задавался). 1 Имена дисководов ”А” и ”В” как правило соответствуют дискетам (НГМД). Современные (1988 г.) НК обычно содержат накопитель на жестких дисках (с именем С), реже — другие устройства с именами Д, Е, F и т. д. — Примеч. пер. 232
Предположим, что вы хотите открыть файл по имени SEQFILE, используя номер файла, равный 1. Предположим далее, что дискета, на которую записывается этот файл,может быть вставле¬ на как в дисковод А, так и в дисковод В. Тогда имя дисковода d следует поместить в переменную, значение которой может быть установлено во время выполнения программы. Следующий оператор откроет файл SEQFILE, а также задаст имя дисковода с помощью строковой переменной DRIVES OPEN DRIVE$+ ”:SEQFILE” FOR OUTPUT AS#1 После того как файл будет открыт, в него можно будет посы¬ лать данные. Это делается с помощью операторов PRINT*, PRINT*USING или WRITE*. Оператором PRINT* пользо¬ ваться сложно, так как при работе с этим оператором программа должна обеспечить вывод между элементами данных специальных разделителей. Аналогичные трудности встретятся и при работе с оператором PRINT*USING, но этот оператор дает возможность форматизировать выводимые данные совершенно так же, как это делается с помощью оператора PRINT USING при выводе данных на экран. Если для пересылки в файл числовых данных приме¬ няется один из этих операторов, то к положительным числам спереди приписывается пробел, как при выводе данных оператором PRINT на экран. Для пересылки данных в файл наиболее удобен оператор WRITE*.Этот оператор автоматически добавляет разделители между данными, помещая после каждого элемента данных либо запятую, либо символ перевода строки. Поэтому, по возможности, пользуйтесь оператором WRITE*, а не PRINT* или PRINT* USING. Оператор WRITE* имеет следующий синтаксис: WRITE# номер-файла, переменная-1, переменная-2, переменная-к Например, для пересылки в файл номер 1 переменных А, В$ и С% вам следует написать такое выражение: WRITE# 1, А, В$, С% При пересылке данных в файл этот оператор вставляет между значениями переменных запятые, а после последнего элемента данных помещает символы возврата каретки и перевода строки. Эти запятые и символы возврата каретки и перевода строки при чтении файла служат разделителями, отделяющими смежные символы. В начало и конец каждой символьной строки добавляют¬ ся кавычки, а численные (целые и действительные) переменные записываются в файл просто как числа, состоящие из символов кода ASCII. В отличие от операторов PRINT* и PRINT* USING, оператор WRITE* не вставляет перед положительными числами пробелы. Если, например, переменные А, В$ и С% имеют соответственно значения 1.2345, «Рога и копыта» и — 32768, то 233
выводимый приведенным выше оператором WRITE* фрагмент файла будет выглядеть таким образом: 1.2345, ’’Рога и копыта”, — 32768,. Если в файл надо записать массив, то лучше всего это сделать с помощью операторов цикла FOR-NEXT. Например, для записи в файл элементов 1—5 массива действительных чисел А(п) можно воспользоваться таким фрагментом программы: 6070 REM — массив действительных чисел 6080 FOR А = 0 ТО 5 6090 WRITE #1, А (А) 6100 NEXT После того как данные будут переданы в файл, его надо закрыть с помощью оператора CLOSE, имеющего следующий формат: CLOSE# номер-файла Для того чтобы, например, закрыть файл номер 1, необходимо выполнить оператор CLOSE# 1. Оператор CLOSE можно исполь¬ зовать и без номера файла, но в таком случае он закроет все файлы на дисках и устройства, открытые на момент его выполне¬ ния. Поэтому в оператор CLOSE желательно включать номер фай¬ ла. Для создания процедуры работы с файлами соединим рас¬ смотренные выше шаги. Для примера составим подпрограмму, которая будет записывать файл SEQFILE. Предположим, что этот файл содержит три массива — строковый, действительный и целочисленный — и три неструктурированных набора переменных тех же типов. Рассматриваемая подпрограмма изображена на рис. 8.1. Строка 6020 программы открывает файл. Строки 6030—6140 содержит цикл FOR-NEXT, в котором в файл записываются три массива. Строки 6160—6180 содержат операторы WRITE, которые записывают в файл три набора переменных, разделяя их запятыми. Строка 6190 содержит оператор CLOSE, который закрывает файл. Если вам не надо закрывать файл внутри подпрограммы, то строка 6190 может быть перемещена в другое место программы. В некоторых случаях оператор CLOSE вообще может быть опу¬ щен, так как при выполнении команд END, NEW, RESET, SYSTEM и RUN, BASIC автоматически закрывает все файлы. Но лучше закрывать файлы с помощью соответствующего оператора. Чтение файлов. Процедура чтения последовательного файла, как и процедура его записи, состоит из трех частей: открытия файла, чтения данных и закрытия файла. Процедуры чтения и записи настолько похожи, что любой здравомыслящий програм¬ мист составляет вначале программу записи, а затем преобразует ее в процедуру чтения с помощью какого-нибудь редактора текстов. 234
0 REH Подпрограмма записи последовательного Файла 1 REM SAVE"А:FIG6-1. BAS", А 6010 REM--Последовательный файл (запись)-- 6020 OPEN DRIVER" : SEQFILE" FOR OUTPUT AS #1 6030 REM-строковый массив- 6040 FOR A:1 TO 5 6050 WRITE#!, A^(A) 6060 NEXT 6070 REH-вещественный массив- 6060 FOR A:1 TO 5 6090 WRITE#1,A(A) 6100 NEXT 6110 REM-целый массив- 6120 FOR A--1 TO 5 6130 WRITE#1, AZ (A) 6140 NEXT 6150 REM-переменные- 6160 WRITE#1, А0ф, AlА2ф:REM строки 6170 WRITE#1, A0, Al, A2:REM вещественные 6180 WRITE#i , A0Z, AlZ, A2Z:REM целые 6190 CLOSE#1:REM закрыть файл 6200 RETURN Рис. 8.1. Подпрограмма записи (создания) последова¬ тельного файла SEQFILE На рис. 8.2 приведена подпрограмма чтения последовательного файла, преобразованная из подпрограммы, изображенной на рис. 8.1. Кроме номеров строк, эти подпрограммы различаются 0 REM Подпрограмма чтения последовательного файла 1 REM SAVE"A:FIG6-2. BAS", А 6250 REM--Последовательный файл(чтение)-- 6260 OPEN DRIVE$+":SEQFILE" FOR INPUT AS #1 6270 REH-строковый массив- 6260 FOR Axl TO 5 6290 INPUT#1,A$(A) 6300 NEXT 6310 REM-вещественный массив- 6320 FOR Az 1 TO 5 6330 INPUT#!, A (A) 6340 NEXT 6350 REM-целый массив- 6360 FOR Azl TO 5 6370 INPUT#1, AZ (A) 5360 NEXT 6390 REM-переменные- 6400 INPUT#!, A0$, Al$, A2$ ©410 INPUT#1, A0, Al, A2 6420 INPUT#1, A0Z, AlZ, A2Z 6430 CLOSE#!:REM закрываем Файл 6440 RETURN P и c. 8.2. Подпрограмма чтения последовательного файла SEQFILE 235
видом оператора открытия файла и тем, что операторы WRITE# заменены на операторы INPUT#. Оператор открытия файла теперь выглядит так: OPEN DR1VE$+ ”:SEQFILE” FOR INPUT AS#1 В операторе открытия файла слово OUTPUT заменено на слово INPUT. Поскольку эта программа почти не отличается от уже разобранной нами программы записи, предоставляем вам возможность разобраться в ней самостоятельно. Преобразование подпрограммы записи в подпрограмму чтения. Подпрограмму записи файла легко преобразовать в подпрограм¬ му его чтения и наоборот. Есть два основных способа выполне¬ ния этой работы. Первый способ заключается в том, что подпро¬ грамму записи выделяют из программы, копируют в отдельный файл, перенумеровывают, преобразовывают, а затем сливают с основной программой. При другом подходе программист все время работает только с текстом основной программы, перенумеро¬ вывая все строки процедуры записи файла и создавая тем самым копию этой процедуры, расположенную в другом месте программы. Оба способа удобны. Они позволяют создавать подпрограмму чтения быстрее, чем если бы вы составляли эту подпрограмму «с нуля». Первый способ имеет то преимущество, что он не требует од¬ новременного отслеживания двух диапазонов строк, поэтому со¬ здаваемая подпрограмма менее подвержена ошибкам. Но в случае коротких подпрограмм рассматриваемое преобразование выпол¬ няется быстрее, если воспользоваться вторым способом. Для превращения подпрограммы записи в подпрограмму чтения после создания ее копии и перенумерации строк в нее сле¬ дует внести такие изменения. • В операторе открытия файла заменить слово OUTPUT на слово INPUT. • Заменить все операторы WRITE# на операторы INPUT#. Испытайте подпрограммы. На рис. 8.3 приведена распечатка коротенькой программы, которая создает некоторый фиктивный набор данных, записывает его в файл SEQFILE, а затем считы¬ вает обратно в память и выводит на экран. В строках 10—160 рас¬ положены операторы присвоения, формирующие набор данных. Строка 170 устанавливает переменную DRIVER равной ”А”, в результате чего упомянутый файл будет записываться на диске, вставленном в дисковод А. Строка 180 вызывает подпрограмму записи файла, пересылая тем самым в него набор данных. Строка 190 удаляет набор данных из оперативной памяти. Строка 200 вновь устанавливает переменную DRIVER равной ”А”, а строка 210 вызывает подпрограмму чтения файла. Остальные строки обеспечивают вывод содержимого файла на экран. Напишите программу, содержащую фрагменты программных 236
текстов, изображенных на рис. 8.1, 8.2 и 8.3. Вы получите возмож¬ ность не только испытать соответствующие программы в работе, но и наблюдать, что произойдет, если изменить содержимое набора данных. Создав файл SEQFILE, вам следует выйти из системы BASIC (с помощью команды SYSTEM), а затем вы¬ вести этот файл на экран. Иначе говоря, вначале, находясь в системе BASIC, наберите команду SYSTEM, а затем, уже нахо¬ дясь в DOS, наберите команду TYPE SEQFILE. Как отмечалось ранее, в данной книге обсуждаются только наиболее фундаментальные вопросы ввода-вывода. Возможно, что вы захотите разобрать некоторые из опущенных мною тем, например изучить оператор APPEND, применяемый для записи данных в конец уже существующих последовательных файлов, оператор EOF, сигнализирующий о конце файла, операторы PRINT# и PRINT#IJSING и операторы LINE INPUT# и INPUT$. 0 REM ,Создание> запись и чтение набора данных 1 REM SAVE"А:FIG8-3. BAS" , А 10 REM--Создание фиктивного набора данных-- 20 DIM А$(5),А(5),AZ(5) 30 FOR А-1 ТО 5 40 А$(A)=STR$(А)♦"строка” 50 А(А)=А«. 123 60 АХ(А)=А 70 NEXT 60 А0фс”А0$" 90 А1$=”А1$Н 100 А2$-”А2$” 110 А0-0 120 А1=1 130 А2х2 140 А0Хх-32767 150 АГ/. = 0 160 А2Х=32767 170 DRIVE$=”A” 100 GOSUB 6010:REM запись файла 190 CLEAR:REM очистка памяти 200 DRIVER "А” 2’10 GOSUB 6250: REM чтение файла 220 REM--Вывод содержимого файла на экран-- 230 CLS 240 FOR А-1 ТО 5 250 PRINT А$(А),А(А),АХ(А) 260 NEXT 270 PRINT А0$,А1$,А2$ 200 PRINT А0,Al,А2 29Й PRINT А0Х,АГХ,А2Х 300 END Рис. 8.3. Программный текст, создающий фиктив¬ ный набор данных, записывающий его в последо¬ вательный файл SEQFILE, а затем считывающим обратно в память 237
ДОКУМЕНТАЦИЯ НА ПОСЛЕДОВАТЕЛЬНЫЙ ФАЙЛ В данной главе уже говорилось о документации, описывались ге сведения о файле, которые следует внести в соответствующие бланки до начала разработки программ. Рекомендуемый формат документации на последовательный файл был приведен в табл. 8.2. Для иллюстрации того, как с помощью этого формата можно документировать реальные файлы, рассмотрим документацию на файл SEQFILE, подпрограммы чтения и записи которого только что рассматривались. В табл. 8.4 показано, что это последовательный файл с именем SEQFILE. При программировании записи и чтения этого файла флажки не использовались, так что соответствующая строка остается пустой. Подпрограмма записи файла начинается в строке 6010, а подпрограмма чтения — в строке 6250. Далее приводятся описания полей, занимаемых каждой пере¬ менной. Так, массив А$(А) содержит фамилии, А(А) —цены и т. д. Максимальное значение индекса каждого из трех массивов, фигурирующее в подпрограммах записи и чтения, равно пяти, что и указано в столбце «Макс, аргумент». Числа, проставленные в графе «Длина», требуют пояснения. Напомним, что содержимое последовательного файла имеет вид ДОКУМЕНТАЦИЯ НА ФАЙЛ Тип файла: последовательный Наименование файла: SEQFILE Флажок: — Номер файла: I Запись файла: строка 6010 Чтение файла: строка 6250 СОДЕРЖАНИЕ ФАЙЛА ОПИСАНИЕ ПОЛЯ МАССИВ/ ПЕРЕМЕННАЯ МАКС. АРГУМЕНТ ДЛИНА ЧИСЛО БАЙТ Наименования А$ (А) 5 24 125 Цены А (А) 5 12 65 Возраст А% (А) 5 6 35 Показатель 1 А0$ 1 12 13 Показатель 2 А1$ 1 12 13 Показатель 3 А2$ 1 12 13 Значение 1 АО 1 8 9 Значение 2 А1 1 8 9 Значение 3 А2 1 8 9 Количество 1 А0% 1 6 7 Количество 2 А1% 1 6 7 Количество 3 А2% 1 6 7 Итого 312 Табл. 8.4. Документация на последовательный файл SEQFILE 238
последовательности символов кода ASCII с разделителями между полями. Длина каждого поля зависит от типа и значения хра¬ нимой в нем переменной. Приведем некоторые общие сведения о длинах полей: • Поле строковой переменной имеет длину, равную числу хранимых в нем символов +2 (на обрамляющие строку кавычки). Например, строка «А» занимает поле длиной 3 символа, строка «АДАМ» — 6, а «МИЗАНТРОП» — 11 символов. • Поле, занимаемое действительным числом двойной точно¬ сти, может иметь длину от 1 до 22 символов. Например, число 1 имеет длину 1, а число — 9.876543210987654D + 29 имеет длину 22 символа. • Действительное число единичной точности может занимать поле длиной от 1 до 12 символов. Например, число 1 имеет длину 1, а число 9.876543Е-|-29 имеет длину 12 символов. • Целое число занимает поле длиной от 1 до 6 символов. Например, число 1 имеет длину 1, а число — 32768 — длину 6. Длины полей были приведены в предположении, что числа записывались в файл оператором WRITE4#. Если положительные числа записывались оператором PRINT# или PRINT#USING, то их длину надо увеличить еще на единицу. Зная тип и предполагаемое содержание поля, можно оценить его длину. Оценивайте с запасом. Размер поля (в байтах) вычис¬ ляется умножением длины поля +1 на число полей (1 добав¬ ляется, чтобы учесть место, занимаемое разделителем). Если выводится массив, то число байт в нем вычисляется по следую¬ щей формуле: Число байт = (Длина поля+ 1) X Число элементов массива. Если поле не является частью массива, то его размер равен просто его длине #1. (Обратите внимание, что число эле¬ ментов в массиве может меняться на единицу в зависимости от того, используется ли элемент с индексом 0.) Следуя приведенным правилам, вы можете определить число байт, зани¬ маемое каждой переменной, а сложив длины всех полей, можете определить длину записи. Длины полей и размер записи файлов произвольного доступа вычисляются иначе, поскольку в таких файлах числа хранятся в кодированном двоичном формате. Мы еще поговорим об этом под¬ робнее. Как уже отмечалось в данной главе, документация на файл нужна при планировании файлов, а затем при их сопровождении. Возможно, вам покажется скучным составлять такую документа¬ цию, но она вам очень хорошо послужит. Если раньше вы такую документацию не готовили, то попробуйте это сделать. Если готовили, то можете себя похвалить. Ну а если подготовка документации для вас привычное дело, я очень рад за вас. 239
ФАЙЛЫ ПРОИЗВОЛЬНОГО ДОСТУПА В данном параграфе рассматриваются необязательные пара¬ метры кдманды вызова интерпретатора BASIC (BASICA), имеющие отношение к файлам произвольного доступа, кодирова¬ ние подпрограмм записи и чтения таких файлов и документация на них. НЕОБЯЗАТЕЛЬНЫЕ ПАРАМЕТРЫ ИНТЕРПРЕТАТОРОВ BASIC И BASICA При обсуждении последовательных файлов рассматривался параметр /F : число-файлов. Этот параметр задается при вызове интерпретаторов языка BASIC. Он определяет максимальное чис¬ ло файлов, которые могут быть одновременно открытыми при выполнении программы. Этот параметр используется и при работе с файлами произвольного доступа. Параметр /S: нужен только при работе с файлами произволь¬ ного доступа. Этот параметр определяет размер буфера, исполь¬ зуемого при пересылке данных в файлы произвольного доступа и обратно. По умолчанию размер буфера устанавливается равным 128 байт. Длина записи файла произвольного доступа не должна превышать размера буфера: в противном случае возникает оши¬ бочная ситуация. Если вы намерены работать с записями длиною более 128 байт, то при загрузке интерпретатора вам следует задать параметр /S:. Параметр /S: записывается после команды BASIC (BASICA). Например, для задания размера буфера, равного 512 байтам, воспользуйтесь такой командой: BASIC /S:512 Обычно одновременно задается также и параметр /Е:число- файлов. Эти два параметра можно объединять в одной команде, например: BASIC /F:4/S:512 ИЛИ BASIC имя-программы /F:4/S:512 Как отмечалось, такая команда может либо вводиться с кла¬ виатуры, либо неявно выдаваться из пакетного файла. Желатель¬ но, чтобы пользователю не надо было вводить сложные команды, поскольку ошибка в задании параметров может вызвать аварийное прекращение работы программы, причем, возможно, не сразу. Доверить эту работу пользователю — все равно, что доверить парашютисту-любителю самому складывать свой парашют: возможно, что он благополучно покинет самолет, но нет никакой гарантии, что и в дальнейшем все будет хорошо. Лучше поместить такую команду вместе с параметрами в пакетный файл, откуда она будет выдаваться быстро и точно. 240
Параметр /S: не должен быть в точности равен длине записи. На \самом деле даже желательно сделать буфер подлиннее. Есл^ во время работы программы файл остается открытым, то в буфере большего объема помещается больше данных, и опера¬ ционная система реже физически записывает их на диск. Фирма IBM рекомендует при работе с файлами произвольного доступа использовать буферы размером 512 байт. Это примерно в четыре раза больше, чем длина записи типичного файла произвольного доступа. Максимальный размер буфера — 32767 байт, так что зна¬ чение параметра /S: не должно превышать этой величины. ПОДПРОГРАММЫ ЗАПИСИ При составлении подпрограмм записи и чтения файлов произ¬ вольного доступа мы следуем тем же соглашениям, что и в случае последовательных файлов. • Подпрограммы работы с файлами располагаются в строках 6000—8999. Поскольку диапазон строк 6000—6440 занят подпрограммами обработки последовательных файлов, для файлов произвольного доступа используются строки с но¬ мерами больше 7000. • Подпрограмма записи предшествует подпрограмме чтения. • Подпрограмма чтения записывается с интервалом в 250 строк после подпрограммы записи. Файл произвольного доступа создается при его открытии. После этого он уже существует и его можно читать даже в том случае, если в этот файл не заносились никакие данные. В этом отношении, как и во многих других, файлы произвольного до¬ ступа отличаются от последовательных файлов. Попытка читать пустой последовательный файл приводит к ошибочной ситуации номер 53: «Файл не найден». С файлами произвольного доступа дело обстоит по-другому. Но читать пустой файл все равно нет смысла: естественнее вначале записать в него информацию. Рабо¬ та с файлами произвольного доступа намного труднее, чем с последовательными файлами. Основной источник трудностей — сложность кодирования ввода-вывода: при обработке файлов произвольного доступа программисту уже недостаточно (как в слу¬ чае последовательного файла) открыть файл, переслать в него данные и закрыть файл. Другой источник осложнений — ограничение на размер запи¬ си файла этого типа. При выводе данных в последовательный файл вы ограничены только количеством свободного места на дис¬ ке, а при чтении — объемом оперативной памяти, необходимой для размещения вводимых данных. Отдельная запись файла произ¬ вольного доступа может в принципе иметь длину до 32767 байт, но если длина записи превышает примерно 1000 байт, кодиро¬ вание программы существенно усложняется. 241
Основное достоинство файлов произвольного доступа заклю¬ чается в возможности очень быстрого доступа к любой записи. Такая возможность обеспечивается благодаря двум обстоятельст¬ вам: тому, что данные хранятся в файле в виде отдельных записей, и тому, что записи состоят из данных, представленных в двоичном формате, которые вводятся и выводятся намного быстрее, чем данные в коде ASCII, из которых состоят последо¬ вательные файлы. / Для записи файла произвольного доступа программа (должна выполнить пять действий: открыть файл, выделить в буфере место для данных, переслать их в буфер, записать буфер с данными в файл и закрыть последний. ' Как открывать файл. Файл открывается при выполнении соответствующих операторов. Существует всего один способ от¬ крыть файл произвольного доступа, причем этот метод позволяет открыть файл как для записи, так и для чтения. В обои(х случаях используется один и тот же оператор, имеющий следующий синтаксис: OPEN ”б:имя-файла” AS n LEN = длина-записи Параметры этого оператора имеют следующий смысл: • d — имя дисковода. Если опустить этот член, то BASIC обратится к дисководу, определяемому по умолчанию; • имя-файла. Имя файла может содержать до восьми симво¬ лов, плюс трехсимвольное расширение; • п — номер файла. Это число от 1 до 15, которое не должно превышать максимума числа файлов, установленного в параметре /F: при вызове интерпретатора BASIC (если этот параметр не задавался, то п должно быть числом от 1 до 3); • длина записи. Суммарная длина всех данных, помещаемых в записи файла. Определяется сложением длин всех полей. Строковые поля имеют длину, равную числу содержа¬ щихся в них символов. Числовые поля хранятся в двоично- кодированной форме и занимают меньше байт, чем обра¬ зующие эти числа символы кода ASCII. Действительные числа двойной точности занимают 8 байт, единичной точно¬ сти — 4 байта, а целые числа — 2 байта. Длина записи не должна превышать 128 байт или объема буфера, зафиксиро¬ ванного в параметре /S: команды загрузки интерпретатора, если этот параметр задавался. Запишем оператор открытия файла, имеющего имя «RANDFILE», номер, равный 1, и длину записи, равную 126: OPEN ’’RANDFILE ”AS # 1 LEN = 126 Этот оператор откроет файл на дисководе, установленном по умолчанию. Если изменить этот оператор: 242
OPEN DRIVE$+”:RANDFILE?’AS#1 LEN = 126 то Дисковод задается значением переменной. Выделение места в буфере файла. Следующий после откры¬ тия файла шаг — выделение в его буфере места под переменные, которые будут записываться в этот файл. Выделение места в бу¬ фере выполняется оператором FIELD. Как и оператор, открываю¬ щий файл, оператор FIELD нужен как при записи, так и при чтении файла. Поэтому эти операторы целесообразно выделить в подпрограмму, которую можно будет вызывать и из подпрограммы записи, и из подпрограммы чтения файла. Оператор FIELD имеет следующий синтаксис: FIELD# номер-файла, длина AS строковая-переменная-1, длина AS строковая- переменная-2,... Параметры этого оператора имеют такой смысл: • номер-файла: номер файла, определенный в операторе, открывшем файл (в предыдущем примере номер-файла равен 1); • длина: длина строковой переменной, представляющей дан¬ ное поле записи файла; ® строковые-переменные: все переменные, перечисляемые в операторе FIELD, должны быть строкового типа. Обычно они используются только в операторе и нигде больше. Числа следует преобразовывать в соответствующие им в операторе FIELD переменные с помощью операторов MKD$, MKS$ и МК1$. Длины соответствующих этим переменным полей определяются по следующему правилу: длина поля строки (т. е. длина поля переменной или кон¬ станты строкового типа) равна числу ее символов; числа двойной точности преобразуются в строки длиной 8 символов; числа единичной точности преобразуются в строки дли¬ ной 4 символа; целое число преобразуется в строку длиной 2 символа. Предположим, что файл последовательного доступа содержит такие переменные: F0$ — название, длина 16 символов; F1S—число двойной точности, длина 8 F2S — число единичной точности, длина F3$ — целое число, длина 2 символа. Место в буфере под эти переменные символов; 4 символа; выделяется следующим оператором: FIELD# 1,16 AS FOS, 8 AS FI$, 4 AS F2$, 2 AS F3$ В одной программе можно употреблять любое число опера¬ торов FIELD, но в каждый момент времени будет действовать только один из' этих операторов. Если вы работаете только с од¬ 243
ним оператором, то ограничиваете объем информации, которую можно поместить в одну запись файла. Действительно, длина строки в языке BASIC не должна превышать 255 символов. Поэтому в операторе FIELD можно упомянуть примерно 25 пере¬ менных (больше не помещается), что соответствует записи длиною, скажем, 1000 символов. Для определения большего числа переменных надо пользоваться специальным приемом опре¬ деления «длинной записи», который будет рассмотрен ниже. Сумма длин всех полей, описанных оператором FIELD, не должна быть больше значения параметра LEN оператора, откры¬ вающего файл. В противном случае произойдет ошибка, называе¬ мая «Переполнением поля». Переменным, фигурирующим в операторе FltZLD, не следует присваивать значения в других частях программы. Если вы так поступите, получившая новое значение переменная переместится из буфера в область строк интерпретатора, что приведет к разру¬ шению указателей буфера файла. Вывод таких переменных на эк¬ ран монитора или на печать вреда не принесет, но все же лучше и безопаснее пользоваться этими переменными исключительно в операторе FIELD и при помещении данных в буфер с помощью операторов LSET и RSET. Избегая их применения в других частях программы, вы уменьшите число переменных, упоминаемых в основной части программы, и тем самым облегчаете ее чтение Кроме того, таким образом вы снижаете риск непреднамеренного присвоения значений этим переменным. Желательно, чтобы фигурирующие в операторе FIELD пере¬ менные назывались просто и были логически связаны друг с дру¬ гом. Воспользуйтесь, например, именами F0$, Fl$, F2$ и т. д. Если вы намереваетесь хранить в записи файла данные, органи¬ зованные как массивы, то назовите массивы переменных F$ (0) — F$(n). Пересылка данных в буфер. Следующим после выполнения опе¬ ратора FIELD шагом будет пересылка данных в буфер. Этот и следующие за ним шаги выполняются только при записи. Дан¬ ные пересылаются в буфер с помощью операторов LSET и RSET. Они имеют такой синтаксис: LSET буферная^—программная$ RSET буферная^ = программная^ Буферная^ обозначает переменную, используемую в операторе FIELD. Программная^^ обозначает имя той же переменной, ис¬ пользуемое в остальной части программы. Если эта переменная не строковая, а числовая, то ее следует преобразовать в строку с помощью функций MKD$, MKS$ или МК1$. Оператор LSET выравнивает буферную^ в соответствующем поле влево, a RSET — вправо. Если и программная переменная, и буферная^ — строковые переменные, то в операторах LSET 244
и RSET эти переменные просто соединяются знаком равенства. Например, если буферная^ есть F0$, а программная^ есть FOWL$, то оператор LSET будет записываться так: LSET FO$ = FOWL$ Если программная переменная является действительным чис¬ лом двойной точности, то для ее преобразования в строку следует воспользоваться функцией MKD$. Если, например, в программу включена переменная LONGNUMB#, а в буфер — Fl$, то опера¬ тор LSET будет выглядеть так: LSET F1$=MKD$(LONGNUMB #) :REM преобразование числа двойной точ¬ ности Аналогично, если в программу включена действительная переменная единичной точности или целочисленная переменная, то для их преобразования в строку применяют соответственно функции MKS$ иМК1$: LSET F2$ = MKS$(MIDNUMB) :REM преобразование числа единичной точности ИЛИ LSET F3$ = MKI$(NODEC%) :REM преобразование целого числа. Запись данных из буфера в файл. После того как данные будут помещены в буфер, их можно записать в файл. Делается это с помощью оператора PUT. Этот оператор имеет следующий синтаксис: PUT# номер-файла, номер-записи Номер-файла — это номер файла, использовавшийся в опера¬ торе, открывавшем этот файл. В предыдущих примерах номер- файла был равен 1. Номером-записи может служить любое число от 1 до 32767. Например, чтобы записать данные в 33-ю запись файла, восполь¬ зуйтесь таким оператором: PUT# 1,33 Обычно в программах номер-записи, в которую пересылаются данные, не является постоянным, поэтому в операторе PUT его можно задавать целочисленной переменной: PUT# 1,RECORD% Как закрывать файл. Запись данных в файл завершается его закрытием с помощью оператора CLOSE. Этот оператор имеет вид CLOSE# номер-файла. Например, файл номер 1 можно закрыть таким оператором: CLOSE# 1 Как уже отмечалось при обсуждении последовательных фай¬ лов, оператор CLOSE можно использовать и без номера файла, но лучше все же задавать его с номером. 245
Давайте теперь объединим пять рассмотренных нами шагов записи данных в файл произвольного доступа — открытие файла, выделение места в буфере, пересылка туда данных, запись буфера в файл и закрытие файла — и составим подпрограмму, которая будет записывать данные в реально существующий файл. Этот файл имеет имя RANDFILE, его номер равен 1, а длина записи равна 126 байтам. В нем будут храниться значения переменных А$(0)—А$(5), А0$, АО#, АО и А0%. Номер записи будет зада¬ ваться целочисленной переменной RECORD%. На рис. 8.4 изображена подпрограмма записи в файл, выпол¬ няющая все необходимые шаги. Эта подпрограмма начинается в строке 7000 и состоит из двух отдельных подпрограмм. 4 REH Подпрограмма записи Файла произвольного доступа 1 REH SAVE"A:FIG8-4. BAS", А 7000 REM'-файл произвольного доступа (запись)-- 7010 GOSUB 7170:REH открываем Файл и определяем поля 7020 REM-Пересылаем данные в буфер файла произвольного доступа- 7030 LSET F0|=A|(0):REM начало пересылки массива 7040 LSET Fli=A|(1) 7050 LSET F2| = A’i(2) 7060 LSET F3$=Ai(3) 7070 LSET F4i=A|(4) 7060 LSET F5i=Ai (5) :REH конец пересьСпки массива 7090 LSET F6|=A0i:REH строка 7100 LSET F7$=MKD|(A0#):REH вещественное число двойной точности 7110 LSET F8$=MKS|(А0):REH вещественное число единичной точности 7120 LSET F9i=HKI$(A0‘Z) : REH целое 7130 REH-Пишем запись- 71 40 PUT# 1 , RECORD Z 7150 CLOSE #1:REH закрываем файл 7160 RETURN 7170 REH--Открываем файл и определяем поля данных-- 7180 OPfai DRIVEI+