Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Delphi_02_04 [2012].doc
Скачиваний:
2
Добавлен:
24.08.2019
Размер:
147.97 Кб
Скачать

Лабораторная работа № 4

Списки

Теоретическая часть

  1. Указатели

Указатель - это специальная переменная, которая хранит адрес ячейки памяти, т. е. указывает на ячейку памяти, в которой хранится нужное значение. В Delphi имеется два типа указателей: типизированные и нетипизированные.

Типизированный указатель объявляется так:

var ИмяУказателя : ^БазовыйТип;

где БазовыйТип - либо идентификатор встроенного типа, либо идентификатор ранее объявленного типа. Например,

var P: Integer;

объявляет переменную P , которая может указывать на любую ячейку памяти, которая содержит значение типа Integer.

В более сложном примере

type TStudent = record

Name: string[20];

Age: Byte;

Group: string[12];

end;

var PStudent: ^TStudent;

объявляется переменная PStudent, которая указывает на начало области памяти, где размещается запись типа TStudent.

Типизированный указатель нельзя использовать до тех пор, пока он не инициализирован. Чтобы инициализировать указатель, ему следует присвоить адрес ячейки памяти. Для этого можно использовать операцию @ или эквивалентную ему функцию Addr. Например,

var I: Integer;

P: ^Integer;

begin

P := @I; // P := Addr(I);

end.

объявляет переменную I типа Integer и переменную Р, которая может указывать на любую ячейку памяти, которая содержит значение типа Integer. После инициализации переменная P указывает на ячейку памяти, в которой хранится значение переменной I.

Чтобы использование указателей было безопасным, следует убедиться, что указатель ссылается на существующую ячейку памяти. Для того чтобы указатель ссылался на несуществующую ячейку памяти, можно воспользоваться зарезервированным словом nil. Оно представляет собой константу, отмечающую несуществующие ячейки памяти. Указатель nil не ссылается ни на одну из ячеек памяти.

После того, как указателю присвоен адрес, указатель можно использовать для изменения значения переменной, на которую он указывает. Для получения доступа к переменной, на которую указывает указатель, необходимо разыменовать указатель, записав символ ^ после имени указателя. Например, после выполнения программы

var X, Y: Integer;

P: ^Integer;

begin

X := 17;

P := @X;

Y := P^;

Writeln(X:10, Y:10, P^:10);

Readln;

end.

будут получены следующие результаты:

17 17 17

Нетипизированный указатель объявляется так:

var ИмяУказателя: Pointer;

Встроенный тип Pointer представляет собой нетипизированный указатель, который может использоваться для указания на переменную любого типа. Чтобы работать со значением, на которое указывает нетипизированный указатель, вначале нетипизированный указатель нужно привести к другому типу указателя и выполнить его разыменование. Например, после выполнения программы

var I: Integer;

C: Char;

P: Pointer;

begin

I := 10;

C := 'A';

P := @I;

WriteLn(I:10, C:10, PInteger(P)^:10);

P := @C;

WriteLn(I:10, C:10, PChar(P)^:10);

ReadLn;

end.

будут получены следующие результаты:

10 A 10

10 A A

Приведение к другому типу указателя не представляет особой сложности, поскольку в Delphi каждый тип данных уже обладает соответствующим типом указателя. Например, указателем на переменную типа Char является PChar, указателем на строку - PString, указателем на целочисленную переменную - PInteger и т. д.

  1. Динамические переменные

Динамические переменные - это переменные, для которых память распределяется в т. н. "куче" (англ. heap), с помощью которой реализована динамически распределяемая память программы. Для размещения и удаления динамических переменных используются подпрограммы «создать объект» (например, New) и «удалить объект» (например, Dispose). По мере создания в программе новых объектов, количество доступной памяти уменьшается. Отсюда вытекает необходимость постоянно освобождать ранее выделенную память. В идеальной ситуации программа должна полностью освободить всю память, которая потребовалась для работы. Некорректное распределение памяти приводит к т. н. «утечкам» памяти, когда выделенная память не освобождается. Многократные утечки памяти могут привести к исчерпанию всей оперативной памяти и нарушению работы программы. Другой проблемой динамического распределения памяти является проблема фрагментации. Выделение памяти происходит блоками - непрерывными фрагментами оперативной памяти. В какой-то момент, в куче попросту может не оказаться блока подходящего размера и, даже, если свободная память достаточна для размещения объекта, операция выделения памяти окончится неудачей. Для управления динамическим распределением памяти используется «сборщик мусора» - программный объект, который следит за выделением памяти и обеспечивает её своевременное освобождение.

В Delphi основными процедурами для динамического распределения памяти являются следующие:

procedure New(var P: Pointer);

Создает новую динамическую переменную и устанавливает на нее указатель P.

procedure Dispose(var P: Pointer);

Уничтожает динамическую переменную, на которую указывает P. Значение P становится неопределенным.

procedure GetMem(var P: Pointer; Size: Integer);

Создает новую динамическую переменную размера Size и устанавливает на нее указатель P.

procedure FreeMem(var P: Pointer[; Size: Integer]);

Уничтожает динамическую переменную данного размера, на которую указывает P. Значение P становится неопределенным.

Пример использования процедур New/Dispose.

program Project1;

{$APPTYPE CONSOLE}

uses SysUtils, Dialogs;

type TStudentPtr = ^TStudent;

TStudent = record

Name : string[20];

Age : Byte;

end;

var p: TStudentPtr;

begin

New(p);

p^.Name := 'Маша Филипенко';

p^.Age := 19;

ShowMessageFmt('%s - %d',[p^.Name, p^.Age]);

Dispose(p);

end.

Пример использования процедур GetMem/FreeMem.

program Project2;

{$APPTYPE CONSOLE}

uses SysUtils, Dialogs;

type TStudentPtr = ^TStudent;

TStudent = record

Name : string[20];

Age : Byte;

end;

var p: TStudentPtr;

begin

GetMem(p, 3 * SizeOf(TStudent));

p^.Name := 'Петров';

p^.Age := 17;

Inc(p);

p^.Name := 'Васечкин';

p^.age := 18;

Inc(p);

p^.name := 'Баранкин';

p^.age := 19;

Dec(p, 2);

ShowMessageFmt('%s - %d',[p^.name, p^.age]);

Inc(p);

ShowMessageFmt('%s - %d',[p^.name, p^.age]);

Inc(p);

ShowMessageFmt('%s - %d',[p^.name, p^.age]);

Dec(p, 2);

FreeMem(p);

end.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]