Учебное пособие-конспект по языку Pascal - Ч. 3, 4

ЧАСТЬ 3. Вариативное, объектное и динамическое программирование.

"Всё течёт, всё изменяется,
и в одну и ту же реку
невозможно войти дважды."
(Гераклит)

"Всё своё ношу с собой."
(Один ещё более известный дрвний грек)

"Брахма творит и уничтожает Вселенные,
которые появляются и исчезают, как пузыри
на поверхности океана во время дождя".
(Из книги "Бхагавад-Гита")

Тема 19. ВАРИАТИВНЫЕ ОПИСАНИЯ И ПАРАМЕТРЫ ОБРАЩЕНИЙ

Хотя вообще-то вариативность (запрограммированная изменяемость) описаний (объявлений) и параметров обращений (аргументов), на первый взгляд, противоречит идеологии канонического Паскаля, опытному программисту удобно её использовать. При некоторых разумных ограничениях на вариативность доказательство нормальности и правильности получившегося алгоритма возможно. Эти разумные ограничения и есть в современных версиях Паскаля. Давайте их освоим.

НЕТИПИЗИРОВАННЫЕ ПАРАМЕТРЫ В ОБРАЩЕНИЯХ
Нетипизированные параметры в обращениях с.129.

ОТКРЫТЫЕ ПАРАМЕТРЫ В ОБРАЩЕНИЯХ
Открытые параметры с.130.

ВАРИАТИВНЫЕ ЗАПИСИ
Вариативные записи Б-Паскаля стр.37 и здесь далее
Для записей вводится возможность ВАРИАНТНЫХ полей записи
(подробнее см. на лекции). Селектор варианта здесь - величина
чисто формальная, т.е. при обращении к записи может даже
отсутствовать. Имена всех полей д.б. различны; константы в полях
должны относиться к упорядоченным типам. Вариантных частей в
записи может быть не более одной, причем она должна
располагаться последней в описании этой записи. Примеры:
type
TPerson=record
Name,SuhrName:string[20];
        Age:integer;
        case Citizen:boolean of
             true : (ResidentCity:string[20]);
             false: (FromCountry:string[30];
                EntryDate,ExitDate :integer);
    end; {TPerson}
type
    Figure=(TRectangle,TTriangle,TCircle,TTrapezion);
TPolygon=record
         x,y:real;
         case shape:figure of
              TRectangle:(Height,Width:real);
              TTriangle:(Angle1,Distance1,
                Angle1,Distance1,
                Angle1,Distance1:real);
              TCircle:(Radius:real);
     end; {TPolygon}

ТИП-ВАРИАНТ
Тип-вариант О-Паскаль Variant
Если на этапе исполнения возможно изменение типов данных в выражениях или в параметрах вызова подпрограмм
Занимает дополнительные 2 байта (информация о фактическом типе переменной).
В переменную-вариант можно поместить фактические переменные: целое, действительное, логическое, строку, время+дату, OLE. Также можно массив, содержащий только эти указанные типы.
Участие в целочисленных, действительных, логических и время+дата выражениях при условии правильности сопряжения фактических данных.
Пример:
var
V1,V2,V3,V4,V5:Variant;
i:integer;
x:real;
s:string;
begin
v1:=1;
v2:=2.73;
v3:='100';
v4:='Жил-был у бабушки серенький козлик.');
i:=v1;
x:=v2;
s:=v4;
v5:=v1+v2+v3;    {получится от такой гибридизации число 103.73}
end.

"ПРОЦЕДУРНЫЙ" ТИП ДАННЫХ
Процедурный тип Борланд с. 50 и с.91


Тема 20. ОБЪЕКТЫ

Идеология объектного программирования: "ОБЪЕКТ = Единое целое,
состоящее из Данных и ОбрабатывающихИхПроцедурИФункций" ,
incapsulation (совмещение, объединение (но не изоляция)),
т.е. смысловая связь процедур и данных - как логическое развитие
идеологии модульного программирования. Итак, ОБЪЕКТ
- это структура из фиксированного количества компонент,
которыми могут быть либо ПОЛЯ {ДАННЫХ}, содержащие данные
определенного типа, либо МЕТОДЫ, описывающие действия,
производимые над объектом.
type {аналогично записям}
TAnyObject=object
               ОписаниеПолейДанных;            {...сначала}
               ПеречислениеЗаголовковМетодов;  {..лишь потом.}
    end;
МЕТОДЫ: процедуры, функции, конструкторы, деструкторы.
Инкапсулированные в объект данные являются "глобальными" по
отношению к любым методам этого объекта.
Описание типа объекта - одно; ЭКЗЕМПЛЯРОВ объекта м.б. сколько угодно.
Обращение к полям и методам объекта - с помощью оператора with
либо путем добавления квалификатора перед именем:
ИмяОбъекта.ИмяЭлементаОбъекта;
Пример:
type
    TPoint=record x0,y0:real; end;
    TObjPoint=object
              x,y,z:real;
              procedure AssignPoint(Zed:TPoint);
    end; {TObjPoint}
procedure TObjPoint.AssignPoint(Zed:TPoint);
begin
X:=Zed.X0;
         Y:=Zed.Y0;
         Z:=0;
end; {AssignPoint}

При обращении к методу ему (автоматически) передается особый
квалификатор self ("свой"), т.е. любой метод объекта работает
как бы с невидимым оператором with ИмяОбъекта do ... .
Квалификатор Self можно указывать и явно.
Пример:
type
TPoint=record x,y:real; end;
    TObjPoint=object
              x,y,z:real;
              procedure AssignPoint(Zed:TPoint);
    end; {TObjPoint}

procedure TObjPoint.AssignPoint(Zed:TPoint);
begin
with Zed do begin
         {<Поля безымянного объекта типа TObjPoint>:=<Значения
           полей объекта (записи) Zed типа TPoint>; }
Self.X := X;
         Self.Y := Y;
    end;
              Z := 0;
end; {AssignPoint}
{ Иногда удобно для указания на непосредственного предка метода
использовать объявление
inherited ИмяМетода;
потому что вызовы квалифицированных методов всегда реализуются
статически, и для динамических (см. далее) методов приходится
избегать квалифицирования}

Внимание ! Объекты можно определять только в глобальном разделе
описания типов программы или модуля.
Внимание ! Объекты не могут являться компонентами файлов.
Внимание ! Область действия компонент объекта выходит за рамки
объекта и его компонентов, поэтому все имена должны быть
уникальными (см. "переопределение").

При "ЭКСПОРТЕ" объектов у компонент, объявленных public
(общедоступными), область действия не ограничивается;
объявленные private (обособленными) - могут использоваться
только в пределах данного модуля.
Пример:
type
    TObjPoint2=object
        public
              x,y,z:real;
              procedure AssignPoint(Zed:TPoint);
        private
              procedure P2;
              constructor C1;
              constructor C2;
              destructor D;
        public
              procedure P3;
    end; {TObjPoint}

НАСЛЕДОВАНИЕ: Объект - "потомок" наследует все данные и методы
объекта - "родителя, пpедка", может их дополнить своими данными и
методами. Наследование обладает свойством транзитивности.
type
ТипПотомок=object(ТипРодитель)   {Только один родитель !}
               НовыеДанные;
               НовыеМетоды;
     end; {ТипПотомок}
Пример:
type
Papa=object x:real; end;                {C полем x}
    Son=object(Papa) y:real; end;           {С полями x,y}

ПОЛИМОРФИЗМ (перопределение): потомок может заменять
методы (внимание: но не данные !) предка на новые.
Пример с разными, но одноименными процедурами M:
type
TA=object procedure M; end;
    TB=object(TA) procedure M; end;
    procedure TA.M; begin write('TA.M там '); end;
    procedure TB.M; begin write('TB.M тут '); end;
var
A:TA; B:TB;
begin
A.M; B.M;   {Напишется: ТА.М там ТВ.М тут}
end.
Внимание !
При переопределении СТАТИЧЕСКОГО (обычного) метода допускается
любое изменение его заголовка; а новое определение ВИРТУАЛЬНОГО
или же ДИНАМИЧЕСКОГО (см. далее) метода должно точно повторять
заголовок вместе с директивой.
Внимание ! Статический метод не может быть перекрыт виртуальным.

При компиляции СТАТИЧЕСКОГО метода устанавливается связь объекта
с нужным методом ("ранняя" линковка (связывание, сборка) объектов
и инкапсуляция в них полей с методами). Обращение к статическим
методам не требует какой-либо особой программной инициализации объекта.
Код вызова ВИРТУАЛЬНОГО метода (м.б. любой, кроме конструктора)
формируется в процессе исполнения программы ("поздняя линковка").
Для этого соответствующий метод д.б. дополнен директивой virtual.
При этом автоматически создается "таблица виртуальных методов"
(ТВМ) - адреса точек входа всех виртуальных методов. Для каждого
типа - своя ТВМ, и каждый относящийся к этому типу экземпляр
пользуется этой общей для них ТВМ. Прежде чем использовать
виртуальный метод, необходимо произвести фактическое связывание
(иначе говоря, инициализировать объект-переменную) посредством
вызова специального метода - constructor. В момент обращения к
конструктору в специальные поля объекта заносится адрес нужной
ТВМ, после чего все виртуальные методы (в т.ч. унаследованные)
получают доступ к нужным полям. Конструктор может не обращаться
ни к какому виртуальному методу и даже быть пустым - все равно
он "сработает".
Пример полиморфизма виртуальных методов, распространяющегося от
потомков к родителям:
Сравните (пpимеpы из [3]):

А) Только статические методы - ранняя сборка: 
type
   TA=object procedure P; function S:string; end;
   TB=object(TA) function S:string; end;      
   procedure TA.P; begin writeln(S); end;
   function TA.S:string; begin S:='TA.S'; end;
   function TB.S:string; begin S:='TB.S'; end;
var
   A:TA; B:TB;
begin
A.P; B.P;  {Напишется ТА.S TA.S}
end.
{...Потому что TB.P = TA.P, а результат TA.P = TA.S  }

Б) С виртуальными методами - поздняя сборка:
type
   TA=object
        procedure P;
        function S:string; virtual;
        constructor Init;
   end; {TA}
   TB=object(TA)
        function S:string; virtual;
        constructor Init;
   end; {TB}      
   procedure TA.P; begin writeln(S); end;
   function TA.S:string; begin S:='TA.S'; end;
   function TB.S:string; begin S:='TB.S'; end;
   constructor TA.Init; begin end;
   constructor TB.Init; begin end;
var
   A:TA; B:TB;
begin
A.Init; B.Init; A.P; B.P;  {Напишется ТА.S TB.S}
end.
{...Потому что результат TB.P = TB.S, а результат TA.P = TA.S  }
Внимание ! Виртуальные методы занимают большую память и вызываются
медленнее, чем статические.

"Маленький хак" (из [3]) : так как TypeOf(ТипОбъекта) возвращает
ссылку на ТВМ для объекта типа ТипОбъекта, то для проверки
гипотезы о том, какой объект является текущим, можно написать
if TypeOf(self)=TypeOf(ПредположительноНашТипОбъекта) then ... .

Секция экспортирования с.107
Конструктор и деструктор подпрграмм с.108
Подпрограммы экзотика с.114

Тема 21. ПАМЯТЬ И АДРЕСА

СТРУКТУРА ПАМЯТИ ЭВМ. АДРЕСА И РАЗМЕЩЕНИЕ КОДОВ И ДАННЫХ.

Функции работы с памятью c.168-169.

Динамическая графика
При работе с графичекой игрушкой-мордочкой, управляемой стрелками, вы уже использовали процедуры динамического выделения памяти под кусок изображения.
GraphGetMem(var Указатель:pointer; Размер:word) – выделяет память (начиная с адреса Указатель) под графические драйверы, шрифты и буфер изображений
GraphFreeMem(var Указатель:pointer; Размер:word) – освобождает память от неиспользуемых графических драйверов.
Указатели на процедурц выделения и освобождения памяти GraphGetMemPtr, GraphFreeMemPtr.
SetGraphBufSize – задать размер графбуфера.


"ОБЫЧНАЯ, или НИЖНЯЯ" память (ПЭВМ типа IBM):  первые 640 К.
"СТАРШАЯ": свыше 640 К до 1024 К  (всего 384 К).
           Частично используется аппаратными средствами.
           Неиспользуемые DOS (свободные) участки старшей
           памяти - "блоки старшей памяти" (UMB).
           Обычно заполняется резидентными программами и драйверами.
"ДОПОЛНИТЕЛЬНАЯ" (XMS): свыше 1 M.
"ВЕРХНЯЯ" (HMA): Первые 64 К дополнительной; обычно используются
                DOS для размещения своих данных и кода программ.
"РАСШИРЕННАЯ" (EMS): остальное. 

Процессор формирует ФИЗИЧЕСКИЙ АДРЕС на основе ЛОГИЧЕСКОГО.

ЛОГИЧЕСКИЙ АДРЕС - 2*2=4 байта: адрес начала выбранного (селектор базы)
СЕГМЕНТА (участок <=64 Кбайт, начинающийся с ФИЗИЧЕСКОГО АДРЕСА,
кратного ПАРАГРАФУ (16 байт) - у рассматриваемого типа ЭВМ), 
и СМЕЩЕНИЕ от начала сегмента до заданной ячейки памяти.
Подробности см. на лекции.

"ДЕЙСТВИТЕЛЬНЫЙ" (Real) РЕЖИМ DOS.
До 1 МБ. Физический адрес 20 бит: селектор начала сегмента
умножается на 16 (сдвиг всех битов на 4 разряда влево)
и суммируется со значением смещения. Размер сегмента =64 К.

"ЗАЩИЩЕННЫЙ" (protected, покрываемый) РЕЖИМ DOS.
До 16 МБ. Принцип построения ОС состоит в предотвращении
пересечения областей памяти нескольких программ, выполняемых
одновременно. Физический адрес 24 бит: селектор начала
выбранного ДЕСКРИПТОРА в таблице дескрипторов (каждый дескриптор -
8 байт: 3 байта - адрес базы выбранного сегмента, ограничители,
флаги разрешения доступа) и величина СМЕЩЕНИЯ от базы сегмента.
Размер сегмента <=64 К.

Любой СЕГМЕНТ может содержать сегмент кода и сегмент данных.
ДАННЫЕ - разрешается читать и изменять.
КОД - инструкции процессора; разрешается только читать (иначе
      объявляется "общая ошибка системы защиты" - General
      Protection Error).
"ДИСПЕТЧЕР ПАМЯТИ" - резидентная программа, оперирующая блоками
памяти, сегментами кода и данных, загрузкой оверлеев и
освобождением памяти.

{Подробнее о защищенном режиме и возможности обхода запрета на
запись в сегмент кода см. на лекции.}

ДЛЯ РЕАЛЬНОГО РЕЖИМА DOS, таблица из [3]:

HeapEnd    -->    Верхняя граница памяти DOS
                Свободная память
HeapPtr    -->    .................
                Динамическая память
HeapOrg    -->    -------------------  <-- OvrHeapEnd
                Буфер оверлея
SSeg:SPtr  -->    -------------------  <-- OvrHeapOrg   (1-й байт за сегментом стека)
                Стек
SSeg:0000  -->    ...................
                Свободная часть стека
DSeg:0000  -->    --------------------       {Значения регистров DS и SS не должны меняться программой}
                Глобальные переменные
                .....................
                Типизированные константы
                -----------------------
                Сегмент кода модуля System
                -----------------------
                Сегмент кода 1-го модуля
                -----------------------
                и т.д.
                -----------------------
                Сегмент кода последнего модуля
                -----------------------
                Сегмент кода основной программы
                -----------------------
                Префикс сегмента программы (PSP) 256 байт
PrefixSeg  -->    -----------------------
                Нижняя граница памяти

При компиляции программ глобальные переменные размещаются
в сегменте данных, а локальные - в сегменте стека.
При компиляции программы С МОДУЛЯМИ все их const и var, объявленные
в интерфейсных частях, помещаются в общий сегмент данных, т.е.
вместе с глобальными const и var основной программы.
Для каждого модуля все коды, а также локальные ("в нем") const и var
помещаются в отдельный соответствующий сегмент.
Объем сегмента данных до 64 К. Объем сегмента стека регулируется
{$M объем} от 1024 до 64 К.

"АБСОЛЮТНЫЕ ПЕРЕМЕННЫЕ" располагаются в точно определенном месте памяти.
Внимание ! В защищенном DOS и в Windows обращение к памяти за пределами
"собственной задачи" запрещается.
Форма 1: absolute сегмент:смещение (оба от $0000 до $ffff):
Пример:
CrtMode: byte absolute $0040:$0049;
Форма 2: размещение в том же месте, где размещена другая переменная:
Пример:
var
    str1:string[40];
    str2:byte absolute str1;
 
Тема 22. УКАЗАТЕЛИ, ДИНАМИЧЕСКИЕ ОБЪЕКТЫ И ОПЕРАТОРЫ

ДИНАМИЧЕСКИЕ ОБЪЕКТЫ. ССЫЛОЧНЫЙ ТИП (указатели).
         АДРЕСНЫЙ ОПЕРАТОР и ДЕЙСТВИЯ НАД ССЫЛКАМИ.

Переменная типа УКАЗАТЕЛЬ имеет своим значением адрес ячейки
памяти, с которой начинается размещение в памяти той переменной,
на которую этот указатель "указывает", т.е. логически связан с ней.

Память для ДИНАМИЧЕСКИХ объектов выделяется не на стадии загрузки,
а на стадии исполнения.

Например, в области "основной памяти" (таблица из [3]):

                -----------------
                Системная область
HeapEnd  -->    -----------------
                "Куча" - незанятая динамическая память
HeapPtr  -->    .................
                Занятая или частично занятая динамическая память
HeapOrg  -->    -----------------
                Программа
                -----------------
                Системная область
0        -->    -----------------

Объявление НЕТИПИЗИРОВАННОГО УКАЗАТЕЛЯ: pointer
Примеры:
type
Tp1=pointer;
var
p1:Tp1;
        p2:pointer;

Объявление ТИПИЗИРОВАННОГО УКАЗАТЕЛЯ:  ^ИмяБазовогоТипа
Примеры:
type
Tp1=^real;
var
p1:Tp1;
        p2:^real;
Внимание ! Типизированный указатель разрешается (как исключение)
объявлять ранее, чем объявление его базового типа.

ОПЕРАЦИИ ПРИСВАИВАНИЯ для типизированных указателей разрешены
только: 1) между указателями, связанными с одним и тем же типом;
        2) между любым типизированным и нетипизированным.
Это повышает безошибочность программ с динамическими объектами.
Пример обхода запрета на присваивание между разнотипными указателями:
var
p1,p2:^integer;
           p3:^real;
            p:pointer;
begin
    p1:=p2; {: Это, очевидно, можно безусловно}
    {p1:=p3;} {: а вот так - нельзя}
    pp:=p3;
    p1:=pp;  {: намеренный обход запрета}
end;

Оператор @ ("оператор ПОЛУЧЕНИЯ АДРЕСА") непосредственно
выдает адрес любого программного ОБЪЕКТА (в т.ч. переменных,
точек входа процедур и т.д., и т.п.).
Пример:
var
p1,p2:pointer;
            x:real;
procedure P;
begin
x:=7;
end;
begin
p1:=@x;
        p2:=@P;
end;

То же самое выдает функция ADDR(x):pointer;

Функции SEG(x):word и OFS(x):word выдают "сегмент" и
"смещение" соответственно адреса программного объекта x.
Будьте внимательны (о символе ссылки ^ см. на пол-страницы
ниже, затем вернитесь сюда): например, если p^:=3.14; то
Seg(p^) - выдает сегмент, где хранится 3.14; а Seg(p) - выдает
сегмент, где хранится p .

УСТАНОВКА значения указателя НА определенную ОБЛАСТЬ ПАМЯТИ
производится функцией PTR(Сегмент,Смещение):pointer;

Процедура NEW(ТипизированныйУказатель) выделяет в верхней
области свободной памяти требуемое место для динамической
переменной и выдает ("возвращает", "сохраняет") начальный адрес
этой области в качестве значения указателя.
Внимание ! Память под любую переменную выделяется порциями,
кратными 8 байтам. Экономьте память !
Примечание: эту процедуру разрешается использовать в форме
функции:  ИмяУказателя:=New(ИмяТипаУказателя);

При размещении динамических ОБЪЕКТОВ можно вызывать
NEW(ТипизированныйУказатель,ИмяКонструктора).
Указатели на объект совместимы по операциям присваивания с
указателями на объекты-предки.
В заголовке динамического метода должен быть указан уникальный
индекс 1..65535 (т.е.64К) :
Пример:   procedure A; virtual 17;

Процедура GetMEM( НЕтипизированныйУказатель, Размер_в_байтах)
создает динамическую переменную с указанным размером занимаемой
памяти (до 64 К) и выдает начальный адрес этой области в качестве
значения указателя.

Для обращения к значению динамической переменной следует указать
имя соответствующего указателя и после него символ ссылки ^ .
Пример:
var
i,j:^integer; r:^real;
begin
new(i); new(r);
    i^:=7; r^:=2*pi;
    writeln(i^,' ',r^:0:2);
end;

Процедура DISPOSE(ТипизированныйУказатель) возвращает обратно
в кучу свободное место в памяти, занятое прежде динамической
переменной.
Внимание ! значение этого указателя при этом НЕ меняется;
в случае повторного применения dispose к свободному указателю
возникает ошибка.

При освобождении динамических ОБЪЕКТОВ можно вызывать
NEW(ТипизированныйУказатель,ИмяДеструктора).

Процедура FreeMEM( НЕтипизированныйУказатель, Размер_в_байтах)
освобождает динамическую память с указанным размером (до 64 К).

Пример:
const
p:^real=nil;
begin
    if p=nil then new(p);
    ...
    dispose(p); p:=nil;
end;

Каждая отдельная динамическая переменная размещается
на НЕПРЕРЫВНОМ участке памяти.

Об ОПТИМИЗАЦИИ РАЗМЕЩЕНИЯ в памяти, диспетчере памяти и
диспетчере (он же администратор) кучи подробно см. на лекции.

Администратор кучи, в частности, изменяет значение указателей
HeapPtr (см. выше) и FreeList - указателя на первое звено цепочки
описателей свободных блоков ниже HeapPtr. Каждое звено описано как
type
     FreeRec=^TFreeRec;
     TFreeRec=record
        Next:pointer;
        Size:pointer; {в старш. - параграф, в младш. - байт 0..15}
     end; {TFreeRec}
Пояснение: здесь размер своб. блока = size.Hi*16+size.Lo  .
Переменная HeapError предназначена для адреса функции обработки ошибок
размещения в динамической памяти. Можно переопределить ее, заменив
тем самым стандартную функцию на другую, "нашу собственную":
HeapError:=@NonStandardHeapErrorFunction;

Во избежание "ячеистой" структуры памяти:
Перед началом выделения динамической памяти текущее значение
HeapPtr можно запомнить в указателе процедурой MARK(Метка-Указатель).
После этого можно в любой момент освободить фрагмент кучи, начиная от
Метки-Указателя, и до конца динамической памяти процедурой
RELEASE(Метка-Указатель).

ПРОЧИЕ процедуры и функции для работы С ПАМЯТЬЮ:

MAXAVAIL:longint; { наибольший НЕПРЕРЫВНЫЙ свободный участок кучи }
MEMAVAIL:longint; { СУММАРНОЕ свободное пространство кучи }
CSEG:word;  { сегмент начала кода программы }
DSEG:word;  { сегмент начала данных программы }
SizeOf(Имя_var_function_procedure_или_type) {длина в байтах
      внутреннего представления указанного объекта или типа}

Пример использования указателей для размещения больших объемов
данных (>>64 K) , написан на основе примера из [3]:

program BigMatrix;
{ А.В. Горшков - Физтех-Колледж }
uses
    crt;
const
     sizeX=200; sizeY=100; sizeOfElement=SizeOf(extended);
     sizeOfString=sizeX*sizeOfElement;
     sizeOfFreeList=2*SizeOf(pointer);
type
    TpElem=^extended; {по 10 байт}
var
   PtrStr: array [0..sizeY-1] of pointer; {Указатели на начала строк матрицы}

function AddressElem(i,j:integer):TpElem; {Адрес элемента [i,j] , где i-номер строки, j-номер столбца}
begin
     AddressElem:=Ptr( Seg(PtrStr[i]^),
                Ofs(PtrStr[i]^)+j*sizeOfElement );
end; {AddressElem}

function GetElem(i,j:integer):extended;  {Прочитать значение элемента}
begin
     GetElem:=AddressElem(i,j)^;
end; {GetElem}

procedure PutElem(i,j:integer; x:extended); { Задать значение элемента}
begin
     AddressElem(i,j)^:=x;
end; {PutElem}

var
   i,j:integer;
   x:extended;
   memav,maxav:longint;
   metkaMatr,metkaStr:pointer;
   {StrMatr:array[0..sizeX-1] of extended;}
begin
   clrscr;
   memav:=MemAvail;
   maxav:=MaxAvail;
   writeln('Всего свободно ',memav,' байт динамической памяти.');
   writeln('В том числе непрерывным участком ',maxav,' байт');
   delay(5000);
   Mark(metkaMatr);

   if (sizeX*sizeY*sizeOfElement+SizeOfFreeList)>MemAvail then begin
      writeln('Матрица не уместится !'); delay(5000); exit;
   end;

   Randomize;

   for i:=0 to sizeY-1 do begin
       Mark(metkaStr);
       if maxAvail>=(sizeOfString+SizeOfFreeList) then begin
          GetMem(PtrStr[i],SizeOfString);
          for j:=0 to sizeX-1 do begin
              PutElem(i,j,1.0*Random(10));
          end;
       end
       else begin
            writeln('Для ',i,'-й строки нет непрерывного места.');
            delay(5000); Release(metkaMatr); exit;
       end;
   end; {for}

   writeln('Размещено все !'); writeln;
   i:=1; j:=1;
   repeat begin
          gotoxy(1,5); clreol;
          writeln('Matrix[',i,',',j,']=',GetElem(i,j):0:2);
          writeln('Введите новое i:'); clreol; readln(i);
          writeln('Введите новое j:'); clreol; readln(j);
   end
   until (i<0) or (j<0);

   Release(metkaMatr);
end.
Тема 23. ДИНАМИЧЕСКИЕ СТРУКТУРЫ ДАННЫХ




Тема 24. БИБЛИОТЕКИ


ЧАСТЬ 4. Элементы системного и низкоуровневого программирования.

Разум – это способность из  хаоса  сделать  космос.
(А.В. Горшков, 1991 г.)

Напомним, что системное и "низкоуровневое" программирование (см. Тему 1) – это "высший пилотаж" для юного (и не только юного) программиста. Во-вторых, это занятие очень трудоёмкое и рискованное, а при недостаточной подготовке программиста порой и не вполне оправданное. Ну что ж – где наша не пропадала! Начнём, благословясь надлежаще.

Тема 25. ОКРУЖЕНИЕ


Тема 26. ЭЛЕМЕНТЫ НИЗКОУРОВНЕВОГО ПРОГРАММИРОВАНИЯ


Тема 27. ВЗАИМОДЕЙСТВИЕ ПРОГРАММ


Тема 28. ДРАЙВЕРЫ И НЕСТАНДАРТНЫЕ ПРЕРЫВАНИЯ

Тема 29. ОПЕРАЦИОННЫЕ СИСТЕМЫ


Давайте остановимся на той мудрой мысли крупнейшего философа из числа гусар – Козьмы Пруткова, каковая давно уже просится на уста: "Нельзя объять необъятного".

_____________________________________     * * * * *     _______________________________________

"Мы строили-строили и наконец построили!"
(Из мультфильма про Чебурашку)

Ну, что сказать в заключение? "Сделал, что смог. Кто сможет, пусть сделает лучше", – как сказал один известный древний римлянин. Желаю вам, уважаемые читатели, успехов в программировании, первым  вашим шагам в котором  я старался помочь. Эх, хорошо отдохнуть после трудового дня! Как говорил легендарный полковник Ходарев (дух которого незримо витал над нами, аки ангелос во небеси) а следом за ним и другие, более материальные, майоры военной кафедры МФТИ, "Скорей бы утро, и снова в поле!" 
:-)


Рецензии