ПРОГРАММИРОВАНИЕ
До сих пор, знакомясь с работой операторов
Spectrum-Бейсика, мы вводили их в непосредственном режиме, то есть наше
требование что-либо сделать компьютер выполнял сразу же после нажатия
клавиши Enter. Для выполнения в этом режиме следующего оператора нужно
опять набирать ключевое слово, параметры и опять нажимать Enter Если бы
компьютер мог работать только так, то он ничем принципиально не
отличался бы от простейшего калькулятора, на котором каждое действие
задается и выполняется отдельно.
Именно способность работать по программе, то
есть выполнять один за другим операторы, расположенные в заданной
последовательности, делает компьютер компьютером. Эта
последовательность операторов и называется компьютерной программой.
Простейший способ заставить компьютер выполнить
несколько операторов подряд без остановки — это после набора
оператора поставить двоеточие, затем ввести следующий, а закончить
последовательность нажатием клавиши Enter:
PRINT "A";: PRINT "В";: PRINT "C";[Enter]
ABC
Однако приведенная строка — еще не
программа. Spectrum не может запомнить эту последовательность
операторов и выполнить вновь. Да и не все операторы Бейс ика можно
записать вот так, в одну строчку. Не говоря уж о том, что читать такую
последовательность не очень удобно.
Программа составляется из множества строк, в
каждой из которых записан один или несколько операторов Строкам
присваиваются «адреса» — номера от 1 до 9999. При
запуске программы строки выполняются одна за другой в порядке
возрастания номеров.
Так, приведенная последовательность операторов PRINT в виде программы запишется следующим образом.
10 PRINT "А";
20 PRINT "В";
30 PRINT "С";
Набор программы
Строки программы набираются точно так же, как и
операторы в непосредственном режиме, только перед первым оператором в
строке обязательно ставится ее номер. После завершения набора
нажимается клавиша Enter, но строка не выполняется, а переписывается в
верхнюю часть основного экрана, освобождая место в строке редактора для
ввода следующей. Именно номер в начале строки сообщает компьютеру, что
набранный оператор или последовательность операторов являются частью
программы, и их не следует выполнять сразу, а нужно поместить в память
компьютера для хранения.
Запуск программы
RUN
Запускается программа оператором RUN, вводимым в непосредственном режиме. После выполнения нашей первой программы на экране увидим
ABC
и знакомое нам сообщение О ОК, 30:1. Смысл его
тот же, только цифры другие. Надеемся, понятные — работа
закончена на первом операторе строки с номером 30.
RUN без параметров запускает программу с первой
строки (со строки с наименьшим номером). Можно «стартовать»
и с любой другой, указав ее номер. Например, оператор RUN 20 запустит
программу с 20-й строки, и на экране появится лишь часть текста:
ВС
Редактирование программы
LIST
При выполнении программы существенным является
лишь порядок следования номеров строк. Поэтому для удобства
последующего изменения программы (например, добавления новых строк)
нумерацию производят через 5 или, чаще, через 10 номеров. Вставляются
строки в программу просто: набирается строка с номером большим, чем
номер строки, после которой нужно сделать вставку, но меньшим, чем
номер последующей, и нажимается Enter. Введем строки
15 PRINT"*"; 25 PRINT "*";
и наша первая программа приобретет следующий вид:
10 PRINT "А"; 15 PRINT"*"; 20 PRINT "В"; 25 > PRINT "*"; 30 PRINT "С";
После ее выполнения (RUN) на экране появится А*В*С
Допустим, нам потребовалось изменить содержание
какой-нибудь строки программы (а этим только и приходится заниматься
при ее отладке). Указать Бейсику строку, которая требует редакции,
можно, перемещая с помощью курсорных клавиш CS/6 и
CS/7 значок >, расположенный в тексте программы на основном экране между строкой и ее номером. Этот значок называется указателем текущей строки
и, пока его «не трогают», указывает на последнюю введенную
строку (в нашем случае на строку 25). Установим указатель на 30-ю
строку и нажмем клавиши CS/1 (Edit). Строка скопируется на служебный
экран, туда, где она ранее набиралась и где ее теперь можно
редактировать. Как это делается, мы уже описывали (см. стр. 9).
Заменим, например, в этой строке букву С на D.
Когда все необходимые изменения в строке
произведены, нажмем Enter. Отредактированная строка перепишется на
прежнее место (если, конечно, не был изменен ее номер).
Пока строка находится на редакции (Enter не
нажата), можно еще отказаться от внесенных в нее изменений. Нужно
нажать CS/1 (Edit), и на редактирование будет вызвана строка, в которой
в данный момент расположен указатель текущей строки. Обратите внимание
на тог что указатель текущей строки можно перемещать и во время редактирования строк.
Для удаления строки из программы совсем
необязательно вызывать ее на редакцию и стирать весь ее текст.
Достаточно ввести ее номер без каких-либо операторов. Введем, к примеру,
10
— и из программы исчезнет 10-я строка
— и номера не останется. Пропадет с экрана и указатель текущей
строки (возвращается он с помощью клавиш CS/6 и CS/7).
И еще одна существенная, но простая операция, которую необходимо освоить для успешной отладки программы — вывод листинга,
то есть распечатка на экране фрагментов программы. Это просто
необходимо, если программа состоит из многих десятков, а то и сотен
строк, которые, естественно, невозможно увидеть на экране сразу все.
Начать вывод листинга с первой строки программы можно с помощью
оператора UST. После его выполнения компьютер представит на экране
первую страницу листинга. Если на ней поместилась не вся программа, то
он спросит: scroll? (прокрутить?). Для продолжения просмотра
(«прокрутки» экрана) нажимается любая клавиша, кроме Space
и CS/Space. После нажатия на эти клавиши вывод листинга прекращается.
spegtrum-бейсик
Можно попросить компьютер вывести листинг программы, начиная с любой строки, указав ее номер после ключевого слова, например:
LIST 20
Причем на упомянутую строку автоматически будет
установлен указатель текущей строки. Таким образом, команда LIST
позволяет быстро «перебрасывать» указатель в любое место
программы.
Вполне может быть, что номер требуемой строки
забылся. Не стоит расстраиваться. Если мы и ошибемся, LIST найдет
строку с ближайшим большим номером и начнет вывод листинга с нее.
Переменные_
LET
До сих пор мы работали с числовыми и
символьными значениями, записанными в явном виде. Результаты действий
не запоминали, а только выводили на экран монитора. В дальнейшей работе
эти результаты использоваться не могли. Для вычисления выражения с
новыми данными приходилось набирать и выполнять новую строку. То есть
действовать так, как будто перед нами не компьютер, а калькулятор. Но
даже в калькуляторах есть такая операция, как запоминание числа.
Занесенное в память, оно может быть извлечено оттуда нажатием одной
клавиши и использовано в дальнейших расчетах. И конечно же, написание
даже самых простейших компьютерных программ немыслимо без сохранения
исходных данных и промежуточных результатов. Причем запоминать надо не
одно, не два числа, а часто сотни и тысячи. И не только числа, но и
слова — строки символов.
Бейсик для хранения числовых и символьных
значений в памяти компьютера отводит специальную область. Заносятся
значения туда с помощью ключевого слова LET.
А для того чтобы ничего не перепутать, каждому из
«сосланных» на хранение значений присваивается собственное
имя. Делается это так:
LET В=3
Этой строкой мы попросили компьютер записать в
память число 3, а место, куда записано число, «обозвать»
именем В. Теперь, чтобы извлечь число, нужно просто
«позвать» его по имени. Например, выполним оператор
PRINT В
- и на экране появится цифра 3. Имя можно
подставить и в выражение. При вычислении значения выражения компьютер,
наткнувшись на имя, заменит его числом из памяти:
PRINT (В+15)/В
6
Значение, занесенное в память, будет храниться
там до тех пор, пока мы либо не сбросим (выключим) компьютер, либо не
выполним операторы RUN или CLEAR (об этом операторе позже), либо не
запишем под этим же именем другое значение. К примеру, выполним:
LET В=5
Именно потому, что записанные в память значения можно в любое время изменять, имена, под которыми они хранятся, называются именами переменных. Сейчас мы работали с переменной по имени В, или просто — с переменной В.
Обратите внимание на то, что переменная в
языках программирования — это нечто другое, чем переменная
величина в математических уравнениях. С точки зрения математики многие
операции, производимые с программными переменными, бессмысленны,
например, вот такая, часто используемая в программировании запись:
LET В=В+1
Приведенный оператор просит компьютер увеличить на единицу содержимое переменной В.
Переменные, предназначенные для хранения чисел, называются числовыми.
Имя числовой переменной может состоять из любого количества цифр и
латинских букв, но не должно начинаться с цифры. Его можно записывать и
строчными, и прописными буквами. Пробелы в имени игнорируются. Приведем
примеры имен числовых переменных:
А; А123; Rub; very long name; very long name
Для хранения символьных значений используются, соответственно, символьные переменные (их иногда также называют строковыми).
Имя символьной переменной может состоять только из одной буквы и знака
$ (доллар). Строчные и прописные буквы в имени не различаются.
Присвоить символьной переменной значение можно с помощью того же
ключевого слова LET:
10 LET A$="BASIC"
— а извлечь из памяти, подставив имя переменной, например, в PRINT:
20 PRINT А$
RUN
BASIC
Символьная переменная может быть приравнена «пустой строке», то есть не содержать ни одного символа:
10 LET А$=""
20 PRINT "♦6"; А$; "###"
RUN
***###
То, что переменная А$ не содержит ни одного символа, хорошо видно по отсутствию интервала между символами 7 и ###.
Все числовые и символьные функции будут
нормально работать, если вместо конкретных значений им
«подсовывать» имена переменных. Конечно, при условии, что
до этого переменная была определена, то есть ей ранее уже присвоено
какое-либо значение. Иначе компьютер выдаст сообщение об ошибке:
Variable not found (переменная не найдена).
Теперь у нас вполне достаточно сведений, чтобы, наконец-то, перейти к написанию программ.
Составим элементарную программу,
пересчитывающую некую сумму в рублях в доллары. По ходу ее написания мы
будем знакомиться с новыми операторами и функциями Бейсика.
Рассчитаем сначала, сколько долларов составляет
установленная нашим государством минимальная зарплата. В момент
написания этой книги она равнялась 900 рублям в месяц. Введем
переменные: Rub, в которую будем заносить сумму в рублях, Dol —
для ее долларового эквивалента и Kurs — курс доллара, то есть
цена одного доллара в рублях (переменную Kurs пока приравняем к 130,
что соответствует нынешнему курсу доллара).
5 REM Программа пересчета рублей в доллары8 10 LET Kurs=130
50 LET Rub=900: PRINT AT 0,1; "Текущий курс: "; Kurs; " рубпей за $P
70 LET Dol=INT(Rub/Kurs*100+0.5)/100: REM Расчет 75 PRINT AT 1, 1; Rub; " руб. - $"; Dol
Сам расчет предельно прост и умещается в
коротенькой строчке под номером 70. Операция с умножением на 100,
извлечением целой части функцией INT (см. стр. 16) и делением на 100
необходимы для округления долларовой суммы до центов. Остальные строки
заняты вводом и выводом информации**.
Запустив программу, увидим на экране:
Текущий курс: 131 рублей за $1 900 руб. - $6.92
Пояснения к тексту программы_
REM
В 5-й строке «всплыл» новый оператор REM (от англ. remark — пометка).
Он сообщает компьютеру, что в этой строке ему делать нечего, можно
спокойно переходить к выполнению следующей. REM можно поставить и после
двоеточия в конце любой строки, как это сделано в строке 70. Вслед за
REM программист пишет для себя или для других программистов комментарии
— пояснения, касающиеся работы программы.
Ввод данных с клавиатуры
во время выполнения программы_
INPUT
Хотя написанная нами программа верно
пересчитывает рубли в доллары, работать с ней неудобно. Для перевода
другой суммы, да еще при постоянно меняющемся курсе, ее надо
редактировать: изменять числа в строках 10 и 50 и снова запускать.
В ситуации, когда данные, необходимые для работы программы, нужно вводить по ходу ее выполнения, поможет оператор INPUT. В простейшем виде он записывается так:
10 INPUT Kurs
Натолкнувшись на него, компьютер останавливает
выполнение программы, выставляет в последней строке экрана курсор и
ждет, пока мы не введем с клавиатуры какое-нибудь число. После
подтверждения ввода клавишей Enter оператор INPUT заносит введенное
число в числовую переменную, имя которой указано вслед за ключевым
словом (в нашем случае в переменную Kurs), и продолжает выполнение
программы. INPUT не успокоится, пока не получит хоть какое-нибудь
число. Если попытаться на запрос ничего не набирать, а сразу нажать
Enter, то он укажет, что мы не правы — выведет знак вопроса (?).
Можно, конечно, вместо числа предложить имя другой числовой переменной.
Тогда переменной, стоящей вслед за INPUT будет присвоено значение
набранной переменной, но только, если последняя ранее была определена.
Иначе программа прервет работу с сообщением об ошибке: Variable not
found.
Вслед за INPUT может стоять и несколько
переменных. В этом случае оператор будет запрашивать числа столько раз,
сколько переменных мы к нему прицепим:
10 INPUT Kurs; Rub
Возможности INPUT этим не исчерпываются. Кроме
ввода данных он еще способен частично исполнять обязанности PRINT
— выводить на экран текст. Используя это его свойство, мы можем
заменить строки 10 и 50 нашей программы одной строкой:
10 INPUT "Текущий курс (руб. за 1$): "; Kurs; " Сумма (руб.): "; Rub
Формат записи данных в INPUT тот же, что и в
PRINT: с теми же кавычками, с теми же знаками препинания. Так же с
помощью PAPER, INK, BRIGHT, FLASH можно управлять атрибутами, а с
помощью AT и TAB — позицией вывода.
Переходы_
GO ТО
Есть еще одно неудобство — нашу программу
после каждого расчета нужно запускать заново. Избавиться от этого
предельно просто — стоит только ввести в действие оператор GO ТО.
Дословно он переводится «пошел на» строку с таким-то
номером:
80 GO ТО 10
Введя эту строку, мы, как говорится,
«зациклим» программу: с последней строки отошлем компьютер
опять к ее началу. Теперь без остановки программы можно пересчитать
цены хоть всех товаров, выпускаемых в России. Но чтобы каждый раз не
вводить курс доллара, все же разнесем ввод данных на две строки и
переход по GO ТО сделаем на строку 35:
5 REM Программа пересчета рублей в доллары 10
INPUT "Текущий курс (руб. за 1$): "; Kurs 33 PRINT AT 0,1; "Текущий
курс: "; Kurs; " рублей за 1$" 35 INPUT " Сумма (руб.): "; Rub 70 LET
Dol=INT(Rub/Kurs*100+0.5)/100: REM Расчет 75 PRINT AT 1, 1; Rub; " руб. - ";"$"; Dol:" 80 GO TO 35
Пробелы (10 штук) в конце 75-й строки призваны затирать «хвост» выведенной в предыдущем расчете суммы.
Останов и продолжение выполнения программы_
STOP, CONTINUE
Теперь возникла другая проблема: как остановить
программу? Не выключать же компьютер. Можно, конечно, сделать сброс, но
тогда сотрется программа.
Вообще, выполнение программы практически в
любом месте можно прервать по команде Break (клавиши CS/Space). На это
компьютер отреагирует одним из сообщений: BREAK Into program
(прерывание во время выполнения программы) либо BREAK -CONT repeats
(прерывание - CONTINUE повторит) и после нажатия Enter перейдет в
редактор Бейсика. Продолжить выполнение программы можно, введя оператор CONTINUE.
Вторую возможность остановить программу дает оператор INPUT. Если на его запрос вместо данных ввести оператор STOP,
то с сообщением STOP In INPUT (стоп при вводе) мы
«вывалимся» из программы. Как и после Break, продолжить
выполнение программы можно по CONTINUE: вновь выполняется оператор
INPUT.
Переходы по условию_
IF...THEN
Требовать от пользователя, не посвященного в
тонкости Бейсика (скажем, от продавца валютного магазина), чтобы он
«вываливался» из программы по Break или STOP, по меньшей
мере, несерьезно. Каждая программа должна корректно и просто
завершаться. И информация о том, как это можно сделать, должна всегда
присутствовать на экране. Например, в таком виде: «Для выхода из
программы нажмите такую-то клавишу».
Поскольку наша программа постоянно ожидает
получения нового числа, то проще всего организовать выход из нее при
условии, что введено 0 руб. Следовательно, нам необходим оператор,
способный проанализировать, равна ли переменная Rub нулю или нет. Если
Rub равна нулю, то необходимо организовать выход из программы, а если
Rub не равна нулю — пересчитать сумму в доллары и перейти к
ожиданию ввода нового числа. Оператор, принимающий подобные решения,
так и выглядит:
IF (если, англ.) <условие> THEN (тогда, англ.) <действие>
< Условием>
может являться любое выражение. На принятие решения: выполнять или не
выполнять действие, указанное за THEN, влияет результат вычисления
этого выражения. Если значение выражения равно нулю, считается, что
условие ложно, не равно нулю — истинно.
Чаще всего в качестве условия, стоящего за IF,
используются выражения сравнения с использованием знаков
«равно» (=), «больше» (>),
«меньше» (<), «больше или равно» (>=),
«неравно» (О), «меньше или равно» (<=).
(Обратите внимание на то, что знаки >=, О и <= вводятся нажатием
клавиш Q, W и Е одновременно с SS).
2 Зак. № 192
< Действие > — ?то любой оператор
Бейсика либо цепочка операторов, разделенных двоеточием. При истинности
условия выполняться будет весь «хвост» строки следом за
THEN.
В нашем примере условием является Rub=0, а
действием — оператор STOP. Программа после включения новых строк
приобретет такой вид:
10 INPUT "Текущий курс (руб. за 1$): "; Kurs
33 PRINT AT 0,1; "Текущий курс: "; Kurs; " рублей за 1$"
34 PRINT AT 15, 0; "Для окончания работы введите 0"
35 INPUT " Сумма (руб.): "; Rub
62 IF Rub=0 THEN STOP
70 LET Dol=INT(Rub/Kurs*100+0.5)/100: REM Расчет
75 PRINT AT 1, 1; Rub; " руб. - ";"$"; Dol:"
80 GO TO 35
Если
условие, стоящее за IF, не выполняется (ложно), то компьютер, не
обращая внимания на THEN, переходит к следующей строке программы.
Ввод символьных данных
INPUT, INPUT LINE
Конечная цель программиста — не написание
программы, которая в принципе как-то работает, а создание такого
продукта, который был бы защищен от ошибочных действий пользователя.
Что, например, произойдет, если при работе с нашей программой ввести
вместо числа букву (это можно сделать и чисто случайно, скажем,
перепутав букву О с цифрой 0)? Программа «вывалится», но не
нормальным образом, а с сообщением об ошибке: Variable not found.
Должны мы предотвратить подобные ситуации? Конечно.
Компьютер не будет ругаться на нажатие любой
клавиши, если попросить оператор INPUT ожидать ввода символьного
значения. Сделать это просто — надо подставить в INPUT вместо
числовой переменной символьную:
35 INPUT " Сумма (руб.): "; R$
На то, что ожидается ввод именно символьного
значения, пользователю укажут кавычки, в которые INPUT заключит курсор
и вводимый текст. От кавычек на экране можно избавиться, если перед
символьными переменными, стоящими за INPUT, ставить ключевое слово LINE:
35 INPUT " Сумма (руб.): "; LINE R$
Хорошо, но в конечном итоге нам ведь ьеобходимо получить число, а не символы.
Символьное значение, введенное с пом< щью INPUT LINE, преобразуем в числовое, используя функцию VaL:
60 LET Rub=VAL R$
К сожалению, этим проблема защиты от ошибочного
ввода не решена. Ведь если теперь будет введено не числовое значение,
то ошибку «выкинет» уже функция VAL. У нас остается один
выход — проверить каждый введенный символ: является ли он цифрой
или нет. Сделать это можно, анализируя коды введенных символов.
Для начала выделим как подстроку первый символ и определим его код:
40 LET Cod=CODE R$(1)
Далее проверим, попадает ли он в интервал от 48
до 57 (коды, соответствующие цифрам от 0 до 9, см. табл. 1 на стр.
100). Если символ не цифра, переходим на строку 100:
42 IF Cod<48 THEN GO ТО 100
45 IF Cod>57 THEN GO TO 100
В 100-й строке мы в дальнейшем организуем обработку ошибки.
Логические операции_
OR, NOT, AND
В этом месте немного отвлечемся от нашей
программы и посмотрим, как можно две строки с номерами 42 и 45,
проверяющие различные условия, заменить одной. Этот частный пример
введет нас в пространство логических операций.
Логика оперирует с несколькими условиями и
помогает делать вывод об истинности или ложности их сочетаний.
Например, в нашей программе необходимо выяснить, выполняется ли хотя бы
одно из двух условий: Cod<48 ИЛИ Cod>57. Нет ничего проще. Надо
только русское ИЛИ заменить на английское, то есть на логический
оператор OR:
Cod<48 OR Cod>57
Это объединенное условие истинно, если верно
любое из сравнений. Учитывая, что истинное выражение принимает значение
1, а ложное — 0, можно записать:
х OR у = 1, если либо х=1, либо у=1, либо и х=1, и у=1
х OR у = 0, только если х=0»и у=0
Проверить, что введенный символ не цифра, можно
и другим способом: выяснить, не попадает ли его код в промежуток от 48
до 57, то есть НЕ выполняются ли одновременно два условия: Cod>48 И
Cod<57. Заменив НЕ на логический оператор NOT, а И — на AND,
запишем:
NOT(Cod>48 AND Cod<57)
Выражение в скоС "ах будет истинно только в том случае, если истинны оба условия. Так и запишем:
х AND у = 1, толы о если х=1 и у=1 х AND у — 0, если либо х=0, либо у=0, либо х=0 и у~0
Логический оператор NOT — это оператор
отрицания. Из истинного утверждения он делает ложно** и, наоборот, из
ложного — истинное:
NOT х = 0, если х=1 NOT х — 1, если х=0
Вот и все логические операции, существующие в
Spectrum-Бейсике. В качестве примера посмотрим, в каком случае может
быть истинно утверждение мальчика Вовочки: «Я сегодня буду есть
мороженое» (доллары пока в сторону). Итак, начнем:
(«Мама даст денег» AND
((«будет работать магазин» AND «там будет мороженое») OR
(«будет работать киоск» AND «там будет мороженое»)) AND NOT «пойдет дождь») OR
(«мороженое принесет папа» AND NOT
«мама оставит мороженое в холодильнике до завтра»)
Вот такая^ ЛОГИКА.
Теперь вместо двух строк нашей
«валютной» программы, проверяющих, что введенный символ
— цифра, можно записать одну:
45 IF CODE R$(1)<48 OR CODE R$(1)>57 THEN GO TO 100
В этой строке мы избавились от лишней переменной Cod.
Такую проверку надо организовать для каждого символа переменной R$, то есть продолжить:
46 IF CODE R$(2)<48 OR CODE R$(2)>57 THEN GO TO 100
Однако если кто-нибудь захочет перевести в
доллары, скажем, 3 рубля (ха-ха!), и, следовательно, переменная R$
будет состоять всего из одного символа, то программа в строке 46
«вылетит» по ошибке (параметр в сечении превысит пределы
допустимого). В подобных случаях необходимо сначала определить длину
символьной переменной и выполнить проверку столько раз, сколько
символов в переменной R$, то есть организовать цикл.
Программные циклы
FOR, ТО, STEP, NEXT
Введем переменную i, называемую счетчиком цикла, присвоим ей значение 1 и подставим в строку 45 для выделения первого
символа переменной — R$(i). После
проверки кода символа увеличим значение i на 1 и сравним его с длиной
переменной R$ (предполагается, что R$ не равна «пустой
строке»). Если i еще не превысила LEN R$, то перейдем снова на
строку 45, выделим из R$ следующий символ (ведь i увеличилась на 1) и
проверим его код:
40 LET i=1
45 IF CODE R$(i)<48 OR CODE R$(i)>57 THEN QO TO 100
48 LET »=i+1
50 IF i<=LEN R$ THEN GO TO 45
Выход из цикла произойдет, когда i превысит количество символов во введенной строке (i>LEN R$).
Конструкция, подобная построенному нами циклу,
настолько часто применяется в программировании, что для ее организации
в Бейсик введены специальные операторы FOR и NEXT. С их помощью наш цикл запишется следующим образом:
40 FOR 1=1 ТО LEN R$
45 IF CODE R$(i)<48 OR CODE R$(i)>57 THEN GO TO 100
50 NEXT i
Следом за ключевым словом FOR следует операция
присвоения переменной I начального значения — эквивалент LET 1=1.
После знака равенства может стоять числовое выражение. Переменная,
использующаяся в цикле FOR...NEXT в качестве счетчика, носит
специальное название — управляющая переменная цикла. Это обычная числовая переменная, но с единственным ограничением: ее имя должно состоять из одной буквы.
За ключевым словом ТО указывается конечное значение
переменной цикла (число либо числовое выражение). Сравнение переменной
цикла и предельного значения осуществляет оператор NEXT, который
ставится в конце цикла с указанной вслед за ним управляющей переменной.
Строка с NEXT i аналогична прежним строкам
48 и 50. NEXT увеличивает переменную цикла и
сравнивает ее с предельным значением. Если значение переменной цикла
превысило конечное значение, то выполнение программы продолжается с
оператора, следующего за NEXT. Иначе делается еще один
«виток»: повторяются все операторы после FOR .
В нашем примере переменная цикла с каждым проходом увеличивается на 1, но значение шага цикла можно варьировать, введя ключевое слово STEP и указав за ним значение, на которое следует увеличивать переменную цикла при выполнении оператора NEXT.
Строку 40 можно записать и так: 40 FOR i=1 ТО LEN R$ STEP 1
Правильность набора нужно проверить не только
при вводе суммы, но и при вводе значения курса доллара. Придется
организовать еще один цикл, подобный уже описанному. Включим в
программу и строку 100, выводящую сообщение о допущенной ошибке, и
строку 105, «отсылающую» к строкам с оператором INPUT, в
которых была допущена ошибка ввода. Номер строки, на которую следует
перейти, заносится в переменную N.
5 REM Программа пересчета рублей в доллары 10 INPUT "Текущий курс (руб. за 1$): "; LINE К$ 13 IF LEN К$=0 THEN GO ТО 10 15 FOR i=1 TO LEN K$
20 IF CODE K$(i)<48 OR CODE K$(i)>57 THEN LET N=10: GO TO 100 25 NEXT i
30 LET Kurs=VAL K$
33 PRINT AT 0,1; "Текущий курс: "; Kurs; " рублей за 1$"
34 PRINT AT 15, 0; "Для окончания работы введите 0"
35 INPUT "Сумма (руб.): "; LINE R$ 37 IF LEN R$=0 THEN GO TO 35
40 FOR i=1 TO LEN R$
45 IF CODE R$(i)<48 OR CODE R$(i)>57 THEN LET N=10: GO TO 100 50 NEXT i
60 LET Rub=VAL R$ 65 IF Rub=0 THEN STOP
70 LET Dol=INT(Rub/Kurs*100+0.5)/100: REM Расчет 75 PRINT AT 1, 1; Rub; " руб. - ";"$"; Dol:" 80 GO TO 35
100 PRINT AT 10, 0;"Извините. Вы ошиблись в наборе."
101 PAUSE 50
103 PRINT AT 10, 0;"
105 GO TO N
Вот теперь компьютер прервет выполнение
программы только тогда, когда мы введем сумму 0 руб. (либо оператор
STOP). При ошибочном вводе компьютер извинится и предложит повторить
набор.
Строки 13 и 37 предохраняют от ввода
«пустой строки», то есть от нажатия Enter без ввода
символов. Если их пропустить, то в строках 30 и 60 программа
«вылетит» по ошибке, не сумев выполнить VAL от
«пустой строки».
Пауза_
PAUSE
В строке 101 программы использован оператор PAUSE.
Он приостанавливает выполнение программы. Длительность паузы задается
параметром оператора в 1/50 долях секунды. Оператор PAUSE 0 задает
бесконечную паузу. Прервать паузу можно и раньше установленного срока,
нажав любую клавишу.
В нашей программе пауза нужна для того, чтобы
пользователь успел прочитать сообщение об ошибке. После чего сообщение
затирается пробелами (строка 103).
Опрос клавиатуры_
INKEY$
Есть еще одна возможность сделать нашу
программу более приятной в общении. При выходе из программы принято
запрашивать подтверждение желания пользователя закончить работу. Ведь
возможна ситуация, когда на запрос случайно будет введен ноль.
Программа прервется, хотя мы этого и не хотели.
Обычно, при необходимости запросить
подтверждение какого-либо действия, программу «зацикливают»
на опросе клавиатуры. Решение «что делать» принимается в
зависимости от того, какая нажимается клавиша. Для опроса клавиатуры
применяется функция INKEY$. Она
не требует аргумента и возвращает символ, соответствующий клавише,
нажатой в данный момент. Если никакая клавиша не была нажата, функция
возвращает значение «пустая строка».
Без предисловий напишем необходимый нам фрагмент программы:
120 PRINT AT 10, 5; "Вы действительно хотите закончить работу? Y/N
(Да/Нет)" 140 IF INKEY$="" THEN GO ТО 140 145 IF INKEY$="Y" OR INKEY$="y" THEN STOP 150 CLS: GO TO 5
Пока никакая клавиша не нажата, программа
«зациклена» на строке 140. Если нажата клавиша Y (с Caps
Shift или без нее), программа останавливается. По любой другой клавише
осуществляется переход к началу программы.
Звук_____
ВЕЕР
Никогда нелишне украсить программу одной-двумя музыкальными фразами.
Spectrum-Бейсик не позволяет создать
многоголосое музыкальное сопровождение, но «насвистеть»
мелодию сумеет. Для этого имеется специальный оператор ВЕЕР. Наберем ключевое слово ВЕЕР, вслед за ним через запятую два числа, скажем, 1 и 0:
ВЕЕР 1, 0
В течение одной секунды мы будем слышать звук с
частотой, соответствующей ноте ДО первой октавы. Меняя первое число,
можно регулировать продолжительность звучания ноты (значение задается в
секундах). Второе число определяет высоту звука: увеличение числа на 1
соответствует переходу на пол тона выше, уменьшение на 1 — на пол
тона ниже. Для поднятия ноты на октаву ко второму параметру ВЕЕР
следует прибавить 12.
Указанный принцип отсчета параметра ВЕЕР не
точен: высоты нот при его использовании не будут совпадать с принятыми
в музыке. Чтобы не травмировать слух окружающих, необходимо
использовать более точные параметры. На рис. 4 приведено точное
соответствие значений второго параметра оператора ВЕЕР нотам первой
октавы.
Для проигрывания мелодии, естественно, нужно написать программку, состоящую из последовательности ВЕЕР. Вот как, к приме-
|
о
|
|
/
|
Zc
|
|
TN о О °
|
V.
|
|
о °
ДО РЕ МИ ФА СОЛЬ ЛЯ СИ ДО (0) (2.039) (3.86) (4.98) (7.02) (8.84) (10.88) (12)
Рис. 4. Точные параметры ВЕЕР для средней октавы.
|
ру, запишется фрагментик из популярной когда-то песни квартета ABBA «Money, money...»:
10 ВЕЕР 0.15,7.02: ВЕЕР 0.15,8.84: ВЕЕР 0.15,10.88
20 ВЕЕР 0.15,7.02: ВЕЕР 0.15,10.88: ВЕЕР 0.75,8.84
30 ВЕЕР 0.15,8.84: ВЕЕР 0.15,8.84: ВЕЕР 0.15,10.88
40 ВЕЕР 0.3,10.88: ВЕЕР 0.6,7.02
Конечно, мы не стали бы занимать место под эту
примитивнейшую программу, если бы не задались целью показать, как ее
можно модифицировать с помощью какого-нибудь, еще не изученного нами
средства.
Массивы
DIM
Первое, что приходит на ум при взгляде на длинную цепочку однотипных операторов ВЕЕР, — это написать цикл типа:
10 FOR i=1 ТО 11 20 ВЕЕР Т, Н 30 NEXT i
Правда, в таком виде программка десять раз
проиграет одну и ту же ноту (длительностью — Т и высотой тона
— Н). Надо каким-то образом менять параметры ВЕЕР при
«прогоне» цикла, то есть необходимо организовать ряд
(набор) переменных и уметь выбирать из этой последовательности нужную,
указывая ее порядковый номер. Тогда можно будет в первую переменную
одной из последовательностей (назовем ее Т(1)) записать длительность
звучания первой ноты, во вторую (Т(2)) — длительность второй ноты
и т. д. Во вторую последовательность H(i) занести одно за другим
значения высот нот. Тогда цикл можно было бы записать следующим образом:
10 FOR i=1 ТО 11 20 ВЕЕР T(i), H(i) 30 NEXT i
Такие последовательности переменных, имеющих одно имя и отличающихся номером {индексом), называются массивами. Переменные, входящие в массив (элементы массива или индексированные переменные),
можно применять как и обычные переменные. Только запись у них немного
другая, да имя должно состоять только из одной буквы. И, конечно, у них
есть огромное преимущество по сравнению с обычными переменными —
их можно обрабатывать одним оператором в цикле, меняя индекс.
Перед применением массива его надо задать
— определить имя и количество элементов в нем. Делается это так:
пишется ключевое слово DIM, а за ним ставятся имя и, в скобках, размерность массива:
5 DIM Т(11): DIM Н(11)
Мы написали «размерность»,
поскольку массивы могут быть не только одномерными (с одним индексом),
но и многомерными (с любым количеством индексов). В этом случае принято
говорить о массивах с несколькими измерениями.
Например, массив, задаваемый строкой DIM А(5, 10), двумерный. Он
состоит из 50 (5x10) индексированных переменных. Для большей
наглядности их можно мысленно расположить в виде таблицы с 5 строками и
10 столбцами:
А(1,1) А(1,2) ... А(1,10) А(2,1) А(2,2) ... А(2,10)
А(5,1) А(5,2) ... А(5,10)
Обращаться с элементами этого массива можно так
же, как и с элементами одномерного: указывай «координаты»
переменной в таблице (номер строки и номер столбца) и работай, как с
обычной переменной: присваивай значения с помощью LET, вставляй в
выражения и т. д.
Для обработки всего массива потребуется уже не
один, а два цикла — один должен быть «вложен» в
другой. Вот, например, как будет выглядеть программа, присваивающая
индексированным переменным значения, соответствующие их индексам, и
распечатывающая массив на экране в виде таблицы:
10 DIM А(5,10) 20 FOR i=1 ТО 5 30 FOR j=1 ТО 10
40 LET A(i,j)=109i+j: PRINT AT 1*2, j*3; A(i,j) 50 NEXT j 50 NEXT i
Массивы могут быть составлены и из символьных
переменных. Массив, заданный строкой DIM S$(10, 5), может
рассматриваться либо как одномерный массив, состоящий из 10 символьных
переменных длиной по 5 символов каждая: S$(1)...S$(10), либо как
двумерный массив из 50 переменны* длиной в один символ:
S$(1,1)...S$(10,5).
Однако мы увлеклись описанием различных
массивов. Пора вернуться к нашей музыкальной программке. Кстати, ведь
ее можно и модернизировать: вместо двух одномерных массивов Т() и Н()
организовать один двумерный. Это напрашивается само собой, ведь по
отдельности эти два массива не имеют смысла:
5 DIM М(11, 2)
10 FOR i=1 ТО 11 20 ВЕЕР M(i, 1), M(i, 2) 30 NEXT i
Все это хорошо, но только при условии, что
каким-то образом элементам массива будут присвоены значения
длительности и высоты нот. Если пойти прямым путем и написать 20
операторов
LET, то мы не только ничего не выгадаем, но, наоборот, сильно увеличим длину программы. Представьте себе конструкцию:
LET М(1,1)=1: LET М(1,2)=2: LET М(2,1)=3
и т. д. до
LET М(11,2)=22
Проще было бы оставить 1 1 операторов ВЕЕР.
Данные в программе
Поскольку значения, указываемые за операторами
DATA, могут быть как числовыми, так и символьными, то необходимо также
следить за порядком их занесения в переменные. Числовые данные должны
считываться в числовые переменные, символьные — в символьные.
Теперь, используя оператор READ, мы можем изящно загрузить параметры мелодии из DATA в массив М():
10 FOR i=1 ТО 11 20 FOR j=1 ТО 2 30 READ M(i, j) 40 NEXT j 50 NEXT i
Правда, получилось, что в компьютере параметры
нашей мелодии хранятся в двух местах: и в тексте самой программы (в
строке за DATA), и в массиве. Это нерационально, и от последнего,
наверное, придется отказаться*.
Используя способность READ последовательно
считывать данные, можно обойтись лишь двумя переменными. Надо только
совместить процесс считывания и проигрывания:
300 FOR 1=1 ТО 11 310 READ Т, Н 320 ВЕЕР Т. Н 330 NEXT i
Теперь эти строки можно использовать в программе.
А если захочется, чтобы мелодия звучала в
нескольких местах программы? Переписать еще раз цикл с READ и ВЕЕР,
конечно, не представит труда, но как быть с данными? Ведь мы их уже
считали. Не дублировать же и их?
Специально для того, чтобы иметь возможность
многократно считывать информацию, записанную в DATA, в Бейсик введен
оператор RESTORE. Он указывает компьютеру, что следующему за ним
оператору READ необходимо считывать данные опять из первого DATA.
Поставив после RESTORE номер строки, в которой
расположен какой-либо промежуточный оператор DATA, можно повторное
считывание начать с него. Таким образом, в нашем примере можно
организовать проигрывание музыкальной фразы с любого места. Надо только
не забыть изменить конечное значение управляющей переменной цикла:
350 RESTORE 210 360 FOR i=1 ТО 5 370 READ Т. Н 380 ВЕЕР Tf Н 390 NEXT i
Хотя и не следовало бы, учитывая возможность
записи и загрузки массивов на магнитную ленту отдельно от основной
программы, что бывает очень удобно. К этому вопросу мы еще вернемся в
разделе, посвященном записи и загрузке информации (см. стр. 49).
Подпрограммы
GO SUB, RETURN
Можно еще как-то смириться с повтором фрагмента
программы длиной в несколько строчек, но довольно часто приходится
использовать по многу раз программные блоки, состоящие, скажем, из
десятков строк. Кому не лень, пусть набирает эти строки несколько раз,
но уважающий себя программист в такой ситуации, не задумываясь,
организует повторение программного фрагмента как вызов подпрограммы. В то место программы, где необходимо использовать ранее написанный блок, он вставит строку
7 GO SUB 290
- что означает: перейти к подпрограмме,
расположенной, начиная со строки 290. То же самое сделал бы и оператор
GO ТО, но с существенной оговоркой: после выполнения подпрограммы
компьютер должен вернуться к оператору, следующему за GO SUB. Дать понять компьютеру, что подпрограмма закончена и пора возвращаться, необходимо с помощью оператора RETURN:
280 REM Подпрограмма для проигрывания мелодии
290 RESTORE
300 FOR i=1 ТО 10
310 READ Т, Н
320 ВЕЕР Т, Н
330 NEXT i
340 RETURN
Вот так будет выглядеть музыкальная подпрограмма. Вызов же ее мы уже оформили (GO SUB 290).
Эту подпрограмму можно сделать более
универсальной, введя в нее две переменные: NResi — номер строки
оператора DATA, начиная с которого нужно считывать данные для
проигрывания фрагмента мелодии, и CoiB — количество нот в
фрагменте. Сама подпрограмма и ее вызов будут выглядеть так:
6 LET NRest=200: LET ColB=11
7 GO SUB 280
77 LET NRest=210: LET Co!B=5: GO SUB 280
280 REM Подпрограмма проигрывания мелодии и ее фрагментов
290 RESTORE NRest
300 FOR i=1 TO ColB
310 READ T, H
320 BEEP T, H
330 IF INKEY$<>"" THEN GO TO 350 340 NEXT i 350 RETURN
В 330 строку мы включили процедуру выхода из
подпрограммы при удержании любой клавиши. Пользователь должен иметь
возможность в любой момент прервать мелодию и приступить (вернуться) к
работе с программой.
При написании сложной по структуре программы
бывает полезно оформлять подпрограммами и неповторяющиеся ее части.
Такую программу легче читать и отлаживать.