РАБОТА С МАССИВАМИ_
SORT, INARRAYO, LENGTH(), COPY, JOIN, DELETE, CHAR$(), NUMBER()
SORT [INVERSE] < символьный масс ив {числовой массив|строка символов >
Этот оператор упорядочивает элементы числового или символьного массива. Числовой массив должен быть одномерным, символьный — либо одномерным, либо двухмерным (одномерный массив символьных строк). В одномерном символьном массиве оператор SORT расставляет символы (в массиве строк — строки) в алфавитном порядке, точнее, в порядке возрастания кодов. Числовой массив сортируется но значениям его элементов от большего к меньшему. Конструкция SORT INVERSE сортирует элементы в обратном порядке.
SORT позволяет почти мгновенно отыскать максимальное и минимальное значения в числовом массиве:
10 DIM А( 100)
20 FOR k=1 ТО 100: LET A(k)=10*RND: NEXT k
30 SORT A(): LET Max=A(1): LET Min=A(100)
40 PRINT "Min=";Min, "Max=";Max
Еще интереснее использовать этот оператор с символьными массивами. Здесь он открывает большие перспективы для создания справочных систем и баз данных.
В символьной строке оператор SORT сортирует символы; в массиве символьных строк переставляет строки, а порядок символов в пределах каждой строки не изменяет. То есгь последовательность строк в массиве становится подобной размещению слов в словаре.
Сферу влияния оператора SORT можно ограничить заданным диапазоном строк с помощью сечения массива, например:
SORT А$(1 ТО 40)
Сортировать массив можно не только по первым символам строк, но и по произвольному сечению, заданному во втором измерении. К примеру, строка
SORT А$(1 ТО 40)(2 ТО)
отсортирует первые 40 строк массива, игнорируя их первый символ.
INARRAY(<массив строк>,<строка-образец>)
По многим свойствам эта функция напоминает функцию INSTRING. Она возвращает номер элемента массива символьных строк, в котором обнаружено первое включение <строки-образца>. На элемент массива (строку), начиная с которой необходимо вести поиск, указывает первый аргумент функции, например:
INARRAY(A$(20),"A")

Эта функция начнет поиск символа А с 20-го элемента массива (то есть с 20-й строки).
COPY <массив 1> ТО <массив 2>
JOIN < массив 1> ТО < массив 2 >
Оба оператора добавляют к <массиву 2> элементы <массива 1>. Оператор COPY копирует указанные элементы, сохраняя их в исходном массиве, a JOIN переносит, не сохраняя оригинал («сшивает» два массива). Поддерживается работа с одно- и двухмерными числовыми и символьными массивами.
Допустимо копировать массивы сами в себя.
Рассмотрим действие этих операторов на примере работы с символьными строками и массивами строк. Операции с числовыми массивами выполняются аналогично. В местах, где наблюдаются некоторые различия, мы сделаем соответствующие оговорки.
10 LET A$="QWERTYUIOP": LET B$="qwertyuiop" 20 COPY A$ TO B$ 30 PRINT "A$=";A$, "B$=";B$
Эта небольшая программка выведет на экран: A$=QWERTYUIOP B$=qwertyuiopQWERTYU!OP
После замены в строке 20 оператора COPY на JOIN выполнение программы прервется на 30-й строке сообщением Variable not found — оператор JOIN ликвидирует переменную А$ после переноса ее содержимого в переменную В$.
Заменим 20-ю строку на 20 COPY А$(4 ТО 6) ТО В$(3)
Результат станет таким:
A$=Q WERTYUIOP B$=qwRTYertyuiop
Применение оператора JOIN с такими же параметрами приведет к следующему:
A$=QWEUIOP B$=qwRTYertyuiop
Таким образом, сечение массива-источника (в нашем случае А$(4 ТО 6)) задает фрагмент, подлежащий переносу или копированию. Номер элемента, указанный в массиве-приемнике, (В$(3)) определяет место в нем, куда будет вставлен соответствующий фрагмент.
При работе с числовыми массивами также допустимо задавать их сечения, используя тот же синтаксис, что и с символьными массивами.
Операции копирования и переноса двухмерных массивов более сложны. Для их анализа Вы можете написать специальную программу. Мы же ограничимся приведением диаграмм, иллюстрирующих работу операторов COPY и JOIN с массивами разных размеров и размерностей (рис. 24). На диаграммах представлены

массивы А() и В() (они могут быть как числовыми, так и символьными), а также результаты выполнения оператора COPY А() ТО В() или JOIN А() ТО В().
но т i=i то з 120 on i
LET Н5Ш LET »=37«
if тм<т тнел
LET a:12S2, Ph0IW=235 ELSE
LET 1=19.03, Phon«:242
131 ПЕХТ i
Рис. 21. Фрагмент листинга программы Beta Basic.
еееее| еввееI
j
1 AAA AAA
ввв ввв
| АААА j АЛЛА
ВВВ I ,ВВВ I АЛА, AAA
ВВВВВ ВВВВВ АААоо АААоо
2)
:в 3) В
. IВВВВВ А) ВВВВВ
Г ввввв!
[ВВВВВ Аоооо I Аоооо IАоооо
АААА АААА
А и В — элементы соответствующих массивов;
о — нулевое значение в числовом массиве или пробел — в символьном.
Рис. 24. Работа COPY и JOIN с двухмерными массивами.
Из этих диаграмм становится ясно, что в случае, когда второе (либо единственное) измерение массива-приемника меньше второго (либо единственного) измерения массива-источника, массив-приемник играет роль «прокрустова ложа» — пристраиваемый фрагмент или весь массив будет усечен по второй размерности до границ своего нового пристанища (случаи 1 и 3).
Если же в новом жилище исходному массиву или его фрагменту слишком просторно (второе измерение массива-приемника больше, чем массива-источника), в этих случаях новые строки символьного массива дополнятся пробелами. В числовых же массивах вместо недостающих элементов будут сгоять нули (случаи 2 и 4).
Для всех вариантов применения оператора JOIN, если не было указано сечение массива-источника, последний будет удален из области переменных.
Синтаксис описываемых операторов допускает использование сечений только по первому измерению.
Как и случае одномерных массивов и символьных строк, двухмерные массивы можно копировать или переносить не только в конец массива-приемника, но и в любое другое его место.
DELETE <массив^символьная переменная)
Оператор удаляет из области переменных символьный или числовой массив либо, если задано сечение массива, его фрагмент. Он г1акже работает с символьными и числовыми переменными, удаляя их из области переменных. Действие оператора DELETE демонстрирует следующая программа:
10 DIM А(30,100)
20 DELETE А(11 ТО 20)
30 PRINT "A(";LENGTH(1 ,"A()");",";LENGTH(2,"A()");")"
Она напечатает: А(20,100), то есть оператор DELETE при указании сечения сокращает массив по первому измерению. В случае работы с символьными строками он позволяет вырезать из них заданные фрагменты. При этом оператор DELETE С$(М ТО N) равносилен строке LET С$=С$( ТО M)+C$(N ТО ).
Удаляя из программы переменные и массивы, отслужившие свой век, DELETE позволяет экономно расходовать память компьютера.
LENGTH!<измерение массива>,"<имя массива)")
Функция LENGTH определяет количество элементов одно- или двухмерного массива (как символьного, так и числового) по каждому его измерению. Номер измерения задается первым аргументом функции, который может принимать значения 1 или 2. Имя массива заключается в кавычки100:
10 DIM А(10,45)
20 PRINT LENGTH(1 ,"А()"), LENGTH(2,"A()")
В результате работы этого примера будут выведены два числа — 10 и 45.
Функция LENGTH позволяет работать с массивом, размеры которого в данной точке программы неизвестны, без опасения выйти за его пределы. Это может понадобиться в процедурах, где универсальный алгоритм рассчитан на работу с массивами, в общем случае имеющими разную длину. Например, программа сортировки элементов одномерного массива (см. стр. 273) может быть переписана так:
10 DIM 0(100)
20 FOR k=1 ТО 100
30 LET G(k)=10*RND
40 NEXT k
SO PROC Limits G(),Emax,Emin
60 PRINT "Min=";Emin, "Max=";Emax 1000 DEF PROC Limits REF F(), REF Max, REF Min 1010 LOCAL Lng,Q() 1020 LET Lng=LENGTH(1/'F()") 1030 DIM Q(1)
1040 COPY F() TO Q(): DELETE Q(1) 1070 SORT INVERSE Q() 1080 LET Min=Q(1): LET Max=Q(Lng) 1090 END PROC
В начале этой программы при помощи генератора случайных чисел формируется массив G() (причем размер массива может быть произвольным), и ссылка на него передается в процедуру Limits (строка 50). В ней вычисляется размер массива F() (процедура «знает» массив G() только под этим именем; строка 1020) и затем его содержимое копируется в массив Q() (строка 1040), объявленный ранее как локальный (строка 1010). Далее идет сортировка (строка 1070) и нахождение предельных значений (строка 1080) по старой схеме. По выходу из процедуры не определенные ранее переменные Emax и Emin будут иметь значения, которые получили в процедуре их alter ego — переменные Мах и Min.
В завершение этого раздела мы расскажем о двух функциях, также позволяющих значительно экономить память при работе с целочисленными массивами:
CHAR$(< число >)
NUMBER (< двухсимвольная переменная >)
Как известно, под хранение любого числа в памяти ZX Spectrum отводится 5 байтов, в то время как для представления целого числа из интервала 0...65535 достаточно только двух. Поэтому целочисленные массивы преимущественно «хранят воздух» — на Vs они заполнены нулями. Бороться с такой непозволительной роскошью помогает функция CHARJ: она представляет числа из интервала 0...65535 двухбайтовыми строками, то есть равносильна следующему набору инструкций:
LET A=INT (N/256): LET B=N-A*256 LET D$=CHR$ A+CHR$ B
- где N — целое число из указанного диапазона.
Функция NUMBER() производит обратную операцию — переводит двухсимвольные строки в форму целых чисел. Аналогом функции является строка:
LET N=256*CODE D$(1)+CODE D$(2)
Ниже мы приводим пример, демонстрирующий экономию памяти, достигаемую с помощью этих функций:
10 DIM D$(500,2)
20 FOR К=1 ТО 500
ВО LET D$(K)=CHAR$(K): NEXT К
40 PRINT МЕМ()
50 DIM N(500)
60 FOR K=1 TO 500
70 LET N(K)=NUMBER(D$(K))
80 NEXT K: DELETE D$()
90 PRINT MEM()
В первом цикле программы с помощью функции CHAR$ из целых чисел от 1 до 500 формируется символьный массив (строки 10...30), после чего на экран выводится количество памяти в байтах, доступной для бейсик-программ (строка 40). Во втором цикле (строки 60...80) функция NUMBER переводит символьный массив в числовой. После удаления символьного массива снова печатается объем свободной памяти. Анализируя результат, можно сделать вывод, что для целочисленного массива размером лишь в 500 элементов преобразование его в двухбайтовое представление дает экономию в полтора килобайта.
РАБОТА С КЛАВИАТУРОЙ_
EDIT, GET
Помимо описанных выше средств программного преобразования символьных строк, Beta Basic позволяет вручную редактировать строковые, а также и числовые данные. Делается это с помощью оператора EDIT, уже знакомого по описанию редактора Beta Basic. В новом амплуа он имеет следующий синтаксис:
EDIT [LINE] < символьная переменная> | < числовая переменная >
По действию оператор EDIT близок к INPUT — он присваивает переменной, указанной следом за ним, соответственно символьное или числовое значение, введенное с клавиатуры. Но в отличие от INPUT, он не отнимает у переменной ее прежнего содержимого, а выводит его в строку служебного экрана для редактирования. Вот небольшой пример:
10 LET A$="QWERTY", B$="qwerty" 20 INPUT "A$="; LINE A$, 30 EDIT "B$="; LINE B$ 40 PRINT "A$=";A$,"B$=";B$
Если при выполнении, этой программки на запросы обоих операторов просто нажать клавишу Enter, то PRINT (строка 40) «покажет», что переменная А$ «опустошилась», а В$ сохранила ранее присвоенное ей значение. Поместив перед именем переменной точку с запятой, можно организовать редактирование и числовых переменных. Если стоящая в EDIT переменная не была к этому моменту определена, то оператор EDIT будет работать как обычный INPUT. В списке из нескольких переменных для всех из них, кроме первой, EDIT тоже работает как INPUT.
Недопустимо подсовывать оператору EDIT «пустую строку» — это может привести к сбросу или зависанию компьютера. Поэтому перед применением EDIT в программе (если нет уверенности) рекомендуется делать проверку неременной на «пустоту»:
IF А$="" THEN INPUT А$: ELSE EDIT А$
GET < символьная переменная {числовая переменная >
Оператор GET производит опрос клавиатуры и присваивает переменной символьное или числовое (в зависимости от того, какая переменна» используется в качестве параметра) значение, соответствующее нажатой клавише, одной или в комбинации с функциональными клавишами CS и SS На нажатие самих функциональных клавиш GET не реагирует. В отличие от функции стандартного Бейсика INKEY$, оператор GET задерживает выполнение программы и ждет, пока не будет нажата клавиша. Он в некоторой степени аналогичен комбинации
PAUSE 0: LET A$=INKEY$
Кроме того, оператор GET позволяет менять режимы курсора во время ожидания нажатия клавиши: он не реагирует на нажатие комбинаций клавиш, задающих тот или иной тип курсора. Используя это свойство, можно считывать символы, возвращаемые клавиатурой не только в режимах курсора [L] или [С], как при работе с функцией INKEY$, но и в режимах [Е] и [GJ.
Оператор GET с числовой переменной в качестве параметра при нажатии цифровых клавиш в режимах курсора [LJ и [С] присваивает ей, соответственно, значения от 0 до 9. При нажатии клавиши А переменной присваивается значение 10, В — 11 и т. д. по алфавиту.
Рассмотрим небольшой пример:
10 PRINT OVER 1 ;"_";CHR$ 8;: GET A$
30 PRINT OVER 1 ;"_";CHR$ 8;: 40 PRINT A$;
50 GO TO 10
Для такой крохотной программки результат неожиданный и впечатляющий: теперь можно свободно перемещать курсор по экрану и вводить символы и ключевые слова в люОом его месте. Чтобы избежать сообщения invalid colour при попытке удалить символ клавишами CS/0, находясь в режиме курсора [Е]*, целесообразно заменить 40-ю строку программы на
40 IF CODE А$<16 OR CODE А$>31 THEN PRINT A$
Согласитесь, получившиеся пять строк — неплохая заготовка для создания полноэкранного редактора программ Beta Basic. Но вот проблема: как включить введенную строку в текст программы? Beta Basic имеет решение и на этот случай: в нем предусмотрен оператор KEYIN, который мы рас смотрим чуть позже.