Версия для печати
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум на Исходниках.RU > Pascal: Общие вопросы > Указатели (Pointers) |
Автор: romtek 07.04.04, 15:18 |
- Указатели - Pointers - В информатике существует целый ряд задач, в которых используются динамические структуры данных. Динамическими структурами данных считаются такие, размер которых заранее неизвестен и (или) изменяется в процессе выполнения программы. Связанные структуры являются динамическими к ним относятся: списки, стеки, очереди, графы, деревья. Динамическое размещение данных предусматривает использование динамической памяти, хотя в ней можно размещать величины любого типа. Динамическая память (куча) - это оперативная память компьютера, предоставляемая программе при её работе за вычетом сегмента данных, стека, памяти используемой системными и резидентными программами, и собственно телом самой исполняемой программы. Размер динамической памяти можно устанавливать из среды или из самой программы специальными директивами компилятора. Куча первоначально всегда свободна и заполняется от нижних адресов в области кучи. За стоянием кучи можно следить при помощи специально предопределённых в языке Pascal переменных типа указатель (Pointer): |
Автор: romtek 07.04.04, 15:29 |
Для работы с указателями необходимо: 1. Описать указатель 2. Задать значение указателю 3. Операция разыменования 4. Освободить динамическую память 1) Описать указатель. При этом в статической области памяти будет выделено 4 байт и связано с его идентификатором. 2) Задать значение указателю <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> Var K: Integer; P: Pointer; ..... P:= Addr(K); { Присвоить адрес переменной K } ..... Функция Addr(X) и операция @X, возвращают значение типа Pointer, являющееся началом области памяти, в которой размещается значение переменной Х. Переменная Х - может быть любого типа. Для выделения динамической памяти величинам при помощи типизированных указателей используется процедура New(TypePtr) <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> , где TypePtr - типизированный указатель. Под действием данной процедуры переменной TypePtr присваивается значение предопределённой переменной HeapPtr, в динамической памяти выделяется место соответственно типу указателя и значение переменной HeapPtr изменяется на величину этого типа. В дальнейшем при помощи этого указателя в динамической памяти можно размещать величины тип, которых соответствует типу типизированного указателя и иметь к ним доступ.Var Ptr :^integer; ....... New(Ptr); Для выделения динамической памяти величинам при помощи нетипизированных указателей используется процедура GetMem(TPtr,Size) <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> , где TPtr - нетипизированный указатель типа Pointer, Size - величина типа Word, количество выделяемой динамической памяти. Под действием данной процедуры переменной TPtr присваивается значение предопределённой переменной HeapPtr, в динамической памяти выделяется участок размером Size байт, значение переменной HeapPtr изменяется на величину параметра Size. В дальнейшем при помощи этого указателя в выделенном учаске динамической памяти можно размещать любые величины размером Size байт и иметь к ним доступ.Var Ptr:Pointer; .......... GetMem(Ptr,50); Для определения количества памяти необходимой для размещения величины какого - либо типа, в языке Pascal определена функция SizeOf(X). <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> , где X - идентификатор переменной, функции или типа. В качестве своего результата функция возвращает величину типа Word - количество памяти в байтах необходимое для размещения X.Var sameVar: byte; K:word; .......... K=SizeOf(sameVar); {k=1} .......... 3) Операция разыменования Суть её состоит в переходе от указателя к значению, на которое он указывает. Эта операци обозначается - идентификатор указателя^ . Результатом операции является значение величины, на которую указывает указатель, т.е. осуществляется доступ к той области памяти, с которой связан указатель. Разыменованному типизированному указателю можно присваивать значения того типа, которым он описан или присваивать его значения переменным того же типа. Аналогично и для нетипизированных указателей, но только надо следить, чтобы размер памяти указанной при создании нетипизированного указателя, совпадал с размером величины, которую мы заносим в память, или в которую мы считываем значение. <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> Var I: ^Integer; R: ^Real; Begin New( I ); New( R ); I^:=200; R^:=3.1456; Writeln(I^); Writeln(R^); {На экран будут выведены значения 200 и 3.1456} End. 4) Освободить динамическую память По окончанию работы с величинами, размещёнными в динамической памяти, её надо освободить от них. Для типизированных указателей определена процедура Dispose(Идентификатор_указателя) <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> После выполнения этой процедуры значение типизированнго указателя неопределено и теряется значение, на которое он указывал. Дальнейшее использование этого указателя возможно, только после присваивания ему значения другого указателя или повторного применения процедуры New. Процедуру Dispose можно применять только к типизированным указателям значение, которых определено.Var Ptr :^integer; ............ new(ptr); ............ dispose(ptr); Для нетипизированных указателей определена процедура FreeMem(P, Size) <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> Var ptr :Pointer; ............ GetMem(ptr,67); ............ FreeMem(ptr,67); , где P указатель типа Pointer, Size величина типа Word (количество освождаемой динамической памяти). Под действием данной процедуры освобождается участок памяти, начиная с адреса находящегося в указателе P, размером.Size. Значение указателя становится неопределённым. Данную процедуру нельзя применять к указателям значение, которых неопределено и следует внимательно следить за размером освобождаемой памяти. Применение этих процедур не изменяет значение переменной HeapPtr ,а освобождаемая динамическая память не учитывается как неиспользованная. На неё не будут указывать указатели при последующих вызовах процедур: New или GetMem. |
Автор: Romtek 14.07.04, 11:18 |
Вот вам и примеры с типизированными указателями В этом примере приводятся способы использования типизированных указателей: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> 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. с нетипизированными указателями В этом примере считывается файл в буффер с применением нетипизированного указателя и выводит количество цифр в нём. <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> 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^[i] 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. Скачать исходники: |