Массивы
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)=10*i+j: PRINT AT i*2, j*3; A(i,j)
50 NEXT j
50 NEXT i
Массивы могут быть составлены и из символьных переменных.
Массив, заданный строкой DIM S$(10, 5), может рассматриваться
либо как одномерный массив, состоящий из 10 символьных пере-
менных длиной по 5 символов каждая: S$(l)...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
Проще было бы оставить 11 операторов ВЕЕР.
Данные в программе_
DATA, READ, RESTORE
Разработчики Бейсика позаботились о нас и включили в него
удобное средство для хранения и загрузки данных в переменные.
Не тех данных, которые вводит в программу пользователь с по-
мощью оператора INPUT, а данных, закладываемых программистом
при ее написании. Например, параметров для операторов ВЕЕР.
Делается это просто: пишется ключевое слово DATA, а за ним
через запятую в нужном порядке размещаются данные. Парамет-
ры нашей мелодии (длительности и высоты нот) запишутся так:
200 DATA 0.15, 7.02, 0.15, 8.84, 0.15, 10.88, 0.15, 7.02, 0.15, 10.88,
0.75, 8.84, 0.15, 8.84, 0.15, 8.84, 0.15, 10.88, 0.3, 10.88, 0.6, 7.02
Данные можно разместить как за одним оператором DATA, так и
распределить между несколькими, то есть разбить строку 200 на
две, три и более строк:
200 DATA 0.15, 7.02, 0.15, 8.84, 0.15, 10.88, 0.15, 7.02, 0.15, 10.88,
0.75, 8.84
210 DATA 0.15, 8.84, 0.15, 8.84, 0.15, 10.88, 0.3, 10.88, 0.6, 7.02
Оператор DATA можно располагать в любом месте программы.
Компьютер игнорирует его и переходит к выполнению следующей
строки. Чаще всего данные помещают за основным текстом про-
граммы, чтобы не затруднять ее чтение.
Как только компьютер встретит оператор READ с одной или
более (через запятую) стоящими за ним переменными, он момен-
тально отыщет строку с DATA и загрузит в эти переменные данные
из DATA. Например:
READ T, Н: PRINT T;" Н
•.15 7.ф2
Первый попавшийся по тексту оператор READ заносит в пере-
менные порцию данных из первого встреченного в программе
оператора DATA. Следующие операторы READ продолжают последо-
вательное считывание. То есть, повторив предыдущую строку, мы
получим уже другой результат:
READ T, Н: PRINT T;" "; Н
•.15 8.84
Следует особо следить за тем, чтобы количество считываний не
превышало количество перечисленных за операторами DATA дан-
ных. Иначе на экране появится сообщение об ошибке: End of data.
Поскольку значения, указываемые за операторами 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 i=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 ВЕЕР Т, Н
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).
Эту подпрограмму можно сделать более универсальной, введя в
нее две переменные: NRest — номер строки оператора DATA, на-
чиная с которого нужно считывать данные для проигрывания
фрагмента мелодии, и ColB — количество нот в фрагменте. Сама
подпрограмма и ее вызов будут выглядеть так:
6 LET NRest=200: LET ColB=11
7 GO SUB 280
77 LET NRest=210: LET ColB=5: GO SUB 280
280 REM Подпрограмма проигрывания мелодии и ее фрагментов
290 RESTORE NRest
300 FOR i=1 TO ColB
310 READ Tf H
320 BEEP Tf H
330 IF INKEY$<>"" THEN GO TO 350
340 NEXT i
350 RETURN
В 330 строку мы включили процедуру выхода из подпрограммы
при удержании любой клавиши. Пользователь должен иметй воз-
можность в любой момент прервать мелодию и приступить (вер-
нуться) к работе с программой.
При написании сложной по структуре программы бывает по-
лезно оформлять подпрограммами и неповторяющиеся ее части.
Такую программу легче читать и отлаживать.