Указатель и динамическая память в Турбо Паскаль

Автор: Пользователь скрыл имя, 18 Января 2012 в 14:01, курсовая работа

Описание работы

Цель курсовой работы является изучение указателя и динамической памяти в Турбо Паскаль.
Для достижения поставленной цели необходимо решить следующие задачи:
- изучить понятия указателей и динамической памяти.
- рассмотреть процедуры и функции с использованием указателей.
- рассмотреть применение указателей и работы с динамической памятью.
- привести пример программы, использующей динамическую память.

Содержание

ВВЕДЕНИЕ 3
1. ПОНЯТИЕ УКАЗАТЕЛЕЙ И ДИНАМИЧЕСКОЙ ПАМЯТИ. 5
1.1 ПОНЯТИЕ ДИНАМИЧЕСКОЙ ПАМЯТИ. 5
1.2 АДРЕСА И УКАЗАТЕЛИ. 6
1.3 ОБЪЯВЛЕНИЕ УКАЗАТЕЛЕЙ. 7
2. ВЫДЕЛЕНИЕ И ОСВОБОЖДЕНИЕ ДИНАМИЧЕСКОЙ ПАМЯТИ. 9
2.1 ИСПОЛЬЗОВАНИЕ УКАЗАТЕЛЕЙ. 13
2.2. ПРОЦЕДУРЫ И ФУНКЦИИ ДЛЯ РАБОТЫ С ДИНАМИЧЕСКОЙ ПАМЯТЬЮ. 16
2.3 АДМИНИСТРАТОР КУЧИ. 19
3. КОНТРОЛЬ ЗА ДИНАМИЧЕСКОЙ ПАМЯТЬЮ. 21
4. ПРИМЕР ПРОГРАММЫ С УКАЗАТЕЛЕМ И ДИНАМИЧЕСКОЙ ПАМЯТЬЮ. 23
ЗАКЛЮЧЕНИЕ 26

Работа содержит 1 файл

КР по основам алгоритмизации.doc

— 277.00 Кб (Скачать)

    var

    i,j:Integer; 

    PtrStr : array [1..100] of pointer;

    const

    SizeOfReal = 6; 

    begin

    for i := 1 to 100 do

    GetMem (PtrStr [i] , SizeOfReal*200) ;

    .......

    {Обращение  к элементу матрицы [i,j]} 

    pr := ptr(seg(PtrStr[i]),

    ofs(PtrStr[i])+(j-1)*SizeOfReal); 

    if рr > 1 then

    .......

    end.

    Поскольку оператор вычисления адреса PR := PTR... будет, судя по всему, использоваться в программе  неоднократно, полезно ввести вспомогательную  функцию GETR, возвращающую значение элемента матрицы, и процедуру PUTR, устанавливающую  новое значение элемента. Каждая из них, в свою очередь, обращается к функции ADDRR для вычисления адреса. В примере 1 приводится программа, создающая в памяти матрицу из NxM случайных чисел и вычисляющая их среднее значение.

    Пример 1 

    const

    SizeOfReal = 6; {Длина переменной типа REAL}

    N = 100; {Количество столбцов}

    М = 200; {Количество строк} 

    var

    i,j : Integer;

    PtrStr: array [1..N] of pointer;.

    s : Real ; 

    type

    RealPoint =^Real;

    {-------------------}

    Function AddrR(i,j: word): RealPoint; 

    {По  сегменту i и смещению j выдает адрес вещественной переменной} 

    begin

    AddrR := ptr(seg (PtrStr [i]),

    ofs{ PtrStr [i]) + (j -1) * SizeOfReal) 

    end {AddrR} ;

    {-------------------}

    Function GetR(i,j: Integer): Real;

    {Выдает  значение вещественной переменной  по сегменту i и смещению j ее адреса}

    begin

    GetR := AddrR(i,j)

    end {GetR};

    {-------------------}

    Procepure PutR(i,j : Integer; x: Real);

    {Помещает  в переменную, адрес которой имеет  сегмент i и смещение j, вещественное  значение x}

    begin

    AddrR ( i , j ) : = x 

    end {PutR};

    {-------------------}

    begin {Main}

    for i :=1 to N do 

    begin

    GetMem (PtrStr [i] , M*SizeOfReal) ; 

    for j := 1 to M do PutR(i, j, Random) 

    end; 

    S := 0;

    for i := 1 to N do 

    for j := 1 to M do

    s := s +GetR(i,j);

    WriteLn(s/(N * М) :12:10)

    end {Main} .

    В рассмотренном примере предполагается, что каждая строка размещается в куче, начиная с границы параграфа, и смещение для каждого указателя PTRSTR равно нулю. В действительности при последовательных обращениях к процедуре GETMEM начало очередного фрагмента следует сразу за концом предыдущего и может не попасть на границу сегмента. В результате, при размещении фрагментов максимальной длины (65521 байт) может возникнуть переполнение при вычислении смещения последнего байта.

    2.2. Процедуры и функции для работы с динамической памятью.

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

    Функция ADDR - возвращает результат типа POINTER, в котором содержится адрес аргумента. Обращение:

    ADDR ( X )

    Здесь Х- любой объект программы (имя любой  переменной, процедуры, функции). Возвращаемый адрес совместим с указателем любого типа.

    Функция CSEG - возвращает значение, хранящееся в регистре CS микропроцессора в начале работы программы в регистре CS содержится сегмент начала кода программы. Обращение:

    CSEG 

    Результат возвращается в слове типа WORD.

    Процедура DISPOSE - возвращает в кучу фрагмент динамической памяти, который ранее был зарезервирован за типизированным указателем. Обращение:

    DISPOSE(TP)

    Здесь ТР - типизированный указатель. При  повторном использовании процедуры  применительно к уже освобожденному фрагменту возникает ошибка периода  исполнения. При освобождении динамических объектов можно указывать вторым параметром обращения к DISPOSE имя деструктора.

    Функция DSEG - возвращает значение, хранящееся в регистре DS микропроцессора (в начале работы программы в регистре DS содержится сегмент начала данных программы). Обращение:

    DSEG 

    Результат возвращается в слове типа WORD.

    Процедура FREEMEM - возвращает в кучу фрагмент динамической памяти, который ранее был зарезервирован за нетипизированным указателем. Обращение:

    FREEMEM ( Р, SIZE )

    Здесь Р - нетипизированный указатель;

    SIZE - длина в байтах освобождаемого  фрагмента.

    При повторном использовании процедуры применительно к уже освобожденному фрагменту возникает ошибка периода исполнения.

    Процедура GETMEM - резервирует за нетипизированным указателем фрагмент динамической памяти требуемого размера. Обращение:

    GETMEM ( Р, SIZE )

    За одно обращение к процедуре можно зарезервировать не более 65521 байтов динамической памяти. Если нет свободной памяти требуемого размера, возникает ошибка периода исполнения. Если память не фрагментирована, последовательные обращения к процедуре будут резервировать последовательные участки памяти, так что начало следующего будет располагаться сразу за концом предыдущего.

    Процедура MARK  - запоминает текущее значение указателя кучи HEAPPTR. Обращение:

    MARK ( PTR )

    Здесь PTR - указатель любого типа, в котором будет возвращено текущее значение HEAPPTR. Используется совместно с процедурой RELEASE для освобождения части кучи.

    Функция MAXAVAIL - возвращает размер в байтах наибольшего непрерывного участка кучи. Обращение:

    MAXAVAIL

    Результат имеет тип LONGINT. За один вызов процедуры NEW или GETMEM нельзя зарезервировать памяти больше, чем значение, возвращаемое этой функцией.

    Функция MEMAVAIL - возвращает размер в байтах общего свободного пространства кучи. Обращение:

    MEMAVAIL 

    Результат имеет тип LONGINT.

    Процедура NEW - резервирует фрагмент кучи для размещения переменной. Обращение:

    NEW ( ТР )

    Здесь ТР - типизированный указатель.

    За  одно обращение к процедуре можно  зарезервировать не более 65521 байта  динамической памяти. Если нет свободной  памяти требуемого размера, возникает ошибка периода исполнения. Если память не фрагментирована, последовательные обращения к процедуре будут резервировать последовательные участки памяти, так что начало следующего будет располагаться сразу за концом предыдущего.

    Процедура NEW может вызываться как функция. В этом случае параметром обращения к ней является тип переменной, размещаемой в куче, а функция NEW возвращает значение типа указатель. Например:

    type

    PInt =^Integer; 

    var

    p: Pint; 

    begin

    p := New(PInt);

    ......

    end.

    При размещении в динамической памяти объекта разрешается в качестве второго параметра обращения к NEW указывать имя конструктора (см. гл.10).

    Функция OFS - возвращает значение типа WORD, содержащее смещение адреса указанного объекта. Вызов:

    OFS ( X ) 

    Здесь Х- выражение любого типа или имя процедуры.

    Функция PTR - возвращает значение типа POINTER по заданному сегменту SEG и смещению OFS. Вызов:

    PTR ( SEG, OFS )

    Здесь SEG - выражение типа WORD, содержащее сегмент;

    OFS - выражение типа WORD, содержащее смещение. 

    Значение, возвращаемое функцией, совместимо с указателем любого типа.

    Процедура RELEASE  - освобождает участок кучи. Обращение:

    RELEASE ( PTR ) 

    Здесь PTR - указатель любого типа, в котором  предварительно было сохранено процедурой MARK значение указателя кучи. Освобождается участок кучи от адреса, хранящегося в PTR, до конца кучи. Одновременно уничтожается список всех свободных фрагментов, которые, возможно, были созданы процедурами DISPOSE или FREEMEM.

    Функция SEG - возвращает значение типа WORD, содержащее сегмент адреса указанного объекта. Вызов:

    SEG ( X ) 

    Здесь X - выражение любого типа или имя  процедуры.

    Функция SIZEOF - возвращает длину в байтах внутреннего представления указанного объекта. Вызов:

    SIZEOF ( X ) 

    Здесь X - имя переменной, функции или  типа. Например, везде в программе из примера 1 вместо константы SIZEOFREAL можно было бы использовать обращение SIZEOF(REAL).

    2.3 Администратор кучи.

    Как уже отмечалось, администратор кучи - это служебная подпрограмма, которая  обеспечивает взаимодействие пользовательской программы с кучей. Администратор кучи обрабатывает запросы процедур NEW, GETMEM, DISPOSE, FREEMEM и др. и изменяет значения указателей HEAPPTR и FREELIST. Указатель HEAPPTR содержит адрес нижней границы свободной части кучи, а указатель FREELIST - адрес описателя первого свободного блока. В модуле SYSTEM указатель FREELIST описан как POINTER, однако фактически он указывает на следующую структуру данных:

    type

    PFreeRec = ATFreeRec; 

    TFreeRec = record

    Next : pointer;

    Size : pointer 

    end;

    Эта списочная структура предназначена для описания всех свободных блоков памяти, которые расположены ниже границы HEAPPTR. Происхождение блоков связано со случайной последовательностью использования процедур NEW-DISPOSE или GETMEM-FREEMEM («ячеистая» структура кучи). Поле NEXT, в записи TFREEREC содержит адрес описателя следующего по списку свободного блока кучи или адрес, совпадающий с HEAPEND, если этот участок последний в списке. Поле SIZE содержит ненормализованную длину свободного блока или 0, если ниже адреса, содержащегося в HEAPPTR, нет свободных блоков. Ненормализованная длина определяется так: в старшем слове этого поля содержится количество свободных параграфов, а в младшем - количество свободных байт в диапазоне 0... 15. Следующая функция преобразует значение поля SIZE в фактическую длину свободного блока:

Информация о работе Указатель и динамическая память в Турбо Паскаль