Учебное пособие-конспект по языку Pascal - Ч. 3, 4
"Всё течёт, всё изменяется,
и в одну и ту же реку
невозможно войти дважды."
(Гераклит)
"Всё своё ношу с собой."
(Один ещё более известный дрвний грек)
"Брахма творит и уничтожает Вселенные,
которые появляются и исчезают, как пузыри
на поверхности океана во время дождя".
(Из книги "Бхагавад-Гита")
Тема 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. ОПЕРАЦИОННЫЕ СИСТЕМЫ
Давайте остановимся на той мудрой мысли крупнейшего философа из числа гусар – Козьмы Пруткова, каковая давно уже просится на уста: "Нельзя объять необъятного".
_____________________________________ * * * * * _______________________________________
"Мы строили-строили и наконец построили!"
(Из мультфильма про Чебурашку)
Ну, что сказать в заключение? "Сделал, что смог. Кто сможет, пусть сделает лучше", – как сказал один известный древний римлянин. Желаю вам, уважаемые читатели, успехов в программировании, первым вашим шагам в котором я старался помочь. Эх, хорошо отдохнуть после трудового дня! Как говорил легендарный полковник Ходарев (дух которого незримо витал над нами, аки ангелос во небеси) а следом за ним и другие, более материальные, майоры военной кафедры МФТИ, "Скорей бы утро, и снова в поле!"
:-)
Свидетельство о публикации №226012500367