| VideoPtr^[i].Symbol:= '+'; { символом '+' в ярко- }
| VideoPtr^[i].Attrib:=15+128 { белом цвете с мерцанием}
| end {for};
| ReadLn; { пауза до нажатия клавиши ввода }
| { Заполнение статического массива Vec: }
| for i:=1 to 100 do Vec[i] := i*3.14;
| MatPtr := Addr(Vec); {передача его адреса ссылке MatPtr}
{Теперь к 100 элементам одномерного массива Vec можно обращаться и как к элементам матрицы 10x10, используя разыменование ссылочной переменной MatrPtr^. Здесь мы распечатаем диагональные элементы матрицы: }
| for i:=1 to 10 do WriteLn(' ':i, MatPtr^[i,i]:-9:2 );
| ReadLn; { пауза до нажатия клавиши ввода }
| { и т.п. }
| END.
Рис. 11.8 (окончание)
Советуем внимательно рассмотреть пример на рис. 11.8. В нем нет ни процедур New/Dispose, ни GetMem/FreeMem! Динамические переменные здесь не создаются и не освобождаются. Взамен этого в ссылки «ручным способом» записываются адреса тех блоков памяти, с которыми мы хотели бы работать. А далее мы обращаемся с ними, как будто они есть структурированные динамические переменные.
Подобная техника открывает доступ к видеопамяти через любые структуры, позволяет проделывать такие вещи, как запись текстов с экрана на диск или их загрузку, подмену структур обращения к данным (как альтернатива приведению типов) и многое другое. Ссылки без кучи в последующих программах-иллюстрациях будут использоваться не раз, особенно при работе с видеопамятью.
11.7. Как организовать структуры, большие чем 64К?
Цифра 64K постоянно преследует разработчика больших программ. Сумма размеров всех глобальных переменных и типизированных констант не может превышать 64K. Размер типа тоже не может превышать 64K:
- 213 -
TYPE { матрица 200x200 }
Dim200x200 = Array [1..200, 1..200] of Real;
В таком описании размер типа равен 200x200x6 байт, что составит более 234К. Компилятор этого ни за что не пропустит, и переменная типа Dim200x200, понятно, не может быть объявлена. С другой стороны, эти 240K вполне могли бы разместиться в средних размеров куче. И это можно сделать!
Нужно лишь реорганизовать этот массив так, чтобы он распался на части, не превышающие по отдельности 64K каждая:
TYPE
Dim200 = Array [1..200] of Real;
Dim200Ptr = ^Dim200;
Dim200x200 = Array [1..200] of Dim200Ptr;
VAR
D : Dim200x200;
Здесь мы определяем тип Dim200 (тип строки матрицы) и тип ссылки на строку Dim200Ptr. После этого определяется тип матрицы 200x200 как статический массив из 200 ссылок на динамические массивы по 200 элементов. Последние вполне могут поместиться в куче. Тем более, что для каждого массива понадобится блок длиной 200x6 байт, а сами эти блоки могут размещаться в разных частях кучи. Размещение такой структуры немного усложнилось:
for i:=1 to 200 do New( D[i] );
как и освобождение:
for i:=1 to 200 do Dispose( D[i] );
Обращение к элементу массива D (разыменование) имеет вид D[i]^[j], где i — номер строки, a j — номер столбца.
Описанный прием достаточно эффективен для многомерных массивов и записей. Таким образом, можно заменять части структуры ссылками на них и забыть про предел в 64K. Но с одномерным массивом так поступить уже нельзя. Придется искать какие-либо обходные пути.
Существует несколько способов хранения данных и их структур, которые ограничены лишь свободным объемом памяти (ОЗУ). К ним относятся списочные структуры, деревья (графы). Отдельно можно выделить структуры типа «стек».
Список — это набор записей, каждая из которых имеет поле данных и указатель (ссылку) на следующую запись в списке. Та, в свою очередь, тоже содержит поле данных и ссылку на продолжение списка. Последний элемент списка (хвост) содержит значение
- 214 -
ки* nil, т.е. уже ни на что не ссылается. Списки легко создаются, добавляются с любого конца; их можно размыкать для вставки нового элемента, исключать элементы и т.д.
* Так напечатано. Видимо при печати пропущена часть текста.—
Мы не будем здесь рассматривать работу со списками. Большинство учебных и справочных изданий по языку Паскаль содержит основные принципы работы с ними.