====== Указатели ====== Для работы с указателями необходимо: - Описать указатель - Задать значение указателю - Операция разыменования - Освободить динамическую память ==== Описать указатель ==== При этом в статической области памяти будет выделено 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.