====== Указатели ======
Для работы с указателями необходимо:
- Описать указатель
- Задать значение указателю
- Операция разыменования
- Освободить динамическую память
==== Описать указатель ====
При этом в статической области памяти будет выделено 4 байт и связано с его идентификатором.
=== нетипизированный ===
Var
Ptr1 : Pointer;
=== типизированный ===
Type
Base = Record
Number : Byte;
Name : String[30];
Phith,Bio,Math : Char;
End;
Lang = Record
Engl,Ukr,Rus : Char;
End;
Mass = Array[1..36] Of Base;
LstPtr = ^List;
List = Record
Number,Ifo :Integer;
end;
Var
BegPtr,EndPtr : LstPtr;
Ptr1 : ^Base;
Ptr2 : ^Mass;
Ptr3 : LstPtr;
Ptr4 : ^String;
Ptr5 : ^Integer;
Ptr6 : ^Real;
==== Задать значение указателю ====
Var
K: Integer;
P: Pointer;
.....
P:= Addr(K); { Присвоить адрес переменной K }
.....
Функция //Addr(X)// и операция //@X//, возвращают значение типа Pointer, являющееся началом области памяти, в которой размещается значение переменной //Х//. Переменная //Х// - может быть любого типа.
Для выделения динамической памяти величинам при помощи **типизированных указателей** используется процедура **//New(TypePtr)//**
Var
Ptr :^integer;
.......
New(Ptr);
, где //TypePtr// - типизированный указатель. Под действием данной процедуры переменной //TypePtr// присваивается значение предопределённой переменной //HeapPtr//, в динамической памяти выделяется место соответственно типу указателя и значение переменной //HeapPtr// изменяется на величину этого типа. В дальнейшем при помощи этого указателя в динамической памяти можно размещать величины тип, которых соответствует типу типизированного указателя и иметь к ним доступ.
Для выделения динамической памяти величинам при помощи **нетипизированных указателей** используется процедура //GetMem(TPtr,Size)//
Var
Ptr:Pointer;
..........
GetMem(Ptr,50);
, где //TPtr// - нетипизированный указатель типа //Pointer//, //Size// - величина типа //Word//, количество выделяемой динамической памяти. Под действием данной процедуры переменной //TPtr// присваивается значение предопределённой переменной //HeapPtr//, в динамической памяти выделяется участок размером //Size// байт, значение переменной //HeapPtr// изменяется на величину параметра //Size//. В дальнейшем при помощи этого указателя в выделенном учаске динамической памяти можно размещать любые величины размером //Size// байт и иметь к ним доступ.
Для определения количества памяти, необходимой для размещения величины какого - либо типа, в языке Pascal определена функция //SizeOf(X)//.
Var sameVar: byte;
K:word;
..........
K=SizeOf(sameVar); {k=1}
..........
, где //X// - идентификатор переменной, функции или типа. В качестве своего результата функция возвращает величину типа //Word// - количество памяти в байтах необходимое для размещения //X//.
==== Операция разыменования ===
Суть её состоит в переходе от указателя к значению, на которое он указывает. Эта операци обозначается - идентификатор указателя^ . Результатом операции является значение величины, на которую указывает указатель, т.е. осуществляется доступ к той области памяти, с которой связан указатель. Разыменованному типизированному указателю можно присваивать значения того типа, которым он описан или присваивать его значения переменным того же типа.\\ Аналогично и для нетипизированных указателей, но только надо следить, чтобы размер памяти указанной при создании нетипизированного указателя, совпадал с размером величины, которую мы заносим в память, или в которую мы считываем значение.
Var
I: ^Integer;
R: ^Real;
Begin
New( I );
New( R );
I^:=200;
R^:=3.1456;
Writeln(I^); Writeln(R^); {На экран будут выведены значения 200 и 3.1456}
End.
==== Освободить динамическую память ====
По окончанию работы с величинами, размещёнными в динамической памяти, её надо освободить от них.
Для **типизированных указателей** определена процедура //**Dispose(Идентификатор_указателя)**//
Var
Ptr :^integer;
............
new(ptr);
............
dispose(ptr);
После выполнения этой процедуры значение типизированнго указателя неопределено и теряется значение, на которое он указывал. Дальнейшее использование этого указателя возможно, только после присваивания ему значения другого указателя или повторного применения процедуры //New//. Процедуру //Dispose// можно применять только к типизированным указателям значение, которых определено.
Для **нетипизированных указателей** определена процедура **//FreeMem(P, Size)//**
Var
ptr :Pointer;
............
GetMem(ptr,67); ............
FreeMem(ptr,67);
, где //P// указатель типа //Pointer//, //Size// величина типа //Word// (количество освождаемой динамической памяти). Под действием данной процедуры освобождается участок памяти, начиная с адреса находящегося в указателе //P//, размером.//Size//. Значение указателя становится неопределённым. Данную процедуру нельзя применять к указателям значение, которых неопределено и следует внимательно следить за размером освобождаемой памяти. Применение этих процедур не изменяет значение переменной //HeapPtr// ,а освобождаемая динамическая память не учитывается как неиспользованная. На неё не будут указывать указатели при последующих вызовах процедур: //New// или //GetMem//.
==== Примеры ====
Вот вам и примеры ;)
=== с типизированными указателями ===
В этом примере приводятся способы использования типизированных указателей:
type
TInfo = record
Size,
Len: integer;
ss: string[20];
end;
Arr = array[1..10] of word;
var
PInteger: ^Integer; { указатель на тип Integer }
PInfo: ^TInfo; { указатель на тип TInfo}
PA: ^Arr; { указатель на тип Arr}
P: Pointer;
Sz,i: word;
begin
writeln;
New (PInteger); { выделение памяти под указатель на тип Integer }
PInteger^ := 123; { значению по адресу PInteger зададим значение }
writeln ('Value = ', PInteger^);
Dispose (PInteger); { освобождение зарезервированной памяти }
New (PA); { выделение памяти под указатель на тип Arr }
for i := 1 to 10 do PA^[i] := i * 2 - 1; { значениям массива по адресу PA зададим значения }
for i := 1 to 10 do write (PA^[i] : 4); { выведем элементы массива по адресу PA }
Dispose (PA); { освобождение зарезервированной памяти }
New (PInfo); { выделение памяти под указатель на тип TInfo}
with PInfo^ do { заносим данные в запись по адресу PInfo }
begin
writeln;
{ вводим значения переменных в записи }
write ('Size: '); readln (Size);
write ('Length: '); readln (Len);
write ('String: '); readln (ss);
writeln (Size:6, Len:6, ss:20); { выводим их значения }
end;
Dispose (PInfo); { освобождение зарезервированной памяти после использования записи }
end.
=== с нетипизированными указателями ===
В этом примере считывается файл в буффер с применением нетипизированного указателя и выводит количество цифр в нём.
var
Digits: word;
procedure AnalizeBlock (Buf: pointer; Sz: word);
type
ByteArr = Array [1..MaxInt] of char;
PByteArr = ^ByteArr;
var
i: word;
P: PByteArr;
begin
P := PByteArr (Buf);
for i := 0 to Sz - 1 do
begin
if P^// in ['0'..'9'] then
inc (Digits);
end;
end;
var
Buffer: Pointer;
F: file;
Size,
Count: word;
begin
writeln;
Assign (F, 'test.dat');
{$I-}
Reset (F, 1);
{$I+}
if IOresult <> 0 then
Halt (-1);
Digits := 0;
Size := 4096;
GetMem (Buffer, Size);
if Buffer <> Nil then
begin
while Not EOF (F) do
begin
BlockRead (F, Buffer^, Size, Count);
AnalizeBlock (Buffer, Size);
end;
FreeMem (Buffer, Size);
end;
Close (F);
writeln ('File contains ', Digits, ' digits.');
end.