Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
программирование на паскале2.doc
Скачиваний:
144
Добавлен:
31.03.2015
Размер:
935.94 Кб
Скачать
    1. Указатели в Паскале

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

Указатели описываются с помощью инструкций:

имя_типированного_указателя: ^тип_содержимого_ячейки;

имя_нетипированного_указателя: pointer;

В качестве типа содержимого ячейки (базового типа) может быть использован любой стандартный тип или имя нестандартного типа.

Указателю может быть присвоено значение другого указа­теля, причем в операторе присваивания (слева и справа от знака:=) должны участвовать указатели с одинаковым базовым типом или один из указателей должен быть нетипированным.

Допустимо сравнивать указатели одного типа на равенство и неравенство.Другие операции сравнения не допустимы.

Операция @означает взятие адреса переменной: @A – адрес переменной A (или адрес первого байта массива или структуры A). Операция^ означает взятие содержимого: ^b – содержимое ячейки с адресом b (сравните положение значка ^ с тем, что используется при объявлении указателей). ^b можно использовать точно так же, как и переменную базового для указателя b типа.

Пример.

Var C: ^integer; i:integer;

Begin C:=@i; {в ячейку С записан адрес ячейки i}

C^:=1; {в ячейку с адресом С записано значение 1}…End.

Имеется встроенная константа nil, представляющая собой пустой или нулевой указатель. Эта константа, естественно, используется при присваивании и сравнении. Значениеnil означает, что указатель не хранит значения адреса какой-либо ячейки памяти. Нельзя путать пустые указатели с неопределенными, в которых может храниться остаточное, мусорное значение. Использование неопределенных указателей очень опасно, так как может привести к несанкционированному обращению к памяти.

Процедура new(p),гдеp– типированный указатель, выделяет область памяти, на которую указывает (т. е. адрес которой хранит)р. При этомp^ представляет собой переменную базового дляртипа и называется динамической переменной. Процедураdispose(p)возвращает выделенную с помощьюnew(p) память в кучу, после примененияdispose(p) значение указателяр становится неопределенным (не становится равнымnil!). Применениеdispose к пустому указателю вызывает сообщение об ошибке.

Процедура GetMem(p,n)выделяет область динамической памяти из n байтов, на которую указываетр– типированный или нетипированный указатель. ФункцияAllocMem(p)возвращает значение нетипированного указателя на область из n байтов; в отличии от GetMem, AllocMemзаполняет выделенную область нулями. ПроцедураFreeMem(p)освобождает память, полученную с помощьюGetMem или AllocMem.

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

Для алгоритмических языков, требующих компиляции, основной трудностью работы со статическими массивами является обязательность указания количества их элементов при объявлении. В частности, в Паскале границами индексов массива в инструкции array могут быть только константы. Единственным способом работы с массивами переменной длины являются динамические переменные.

Классический подход к работе с массивами переменной длины, который в настоящее время используется, например, в алгоритмическом языке Си, состоит в следующем. После определения числа nэлементов массива (например, посредством ввода) с помощью процедуры, аналогичнойGetMem(p,n),выделяется область памяти под массив. Указательpпри этом ссылается на первый элемент массива. Адреса остальных элементов легко вычисляются по их индексам. Например, адрес i-го элемента в одномерном массиве равен p+(i-1)*s, где s – количество байтов, занимаемых одним элементом. В Объектном Паскале такой подход невозможен, так как ограничено использование арифметических операций над указателями. Это ограничение позволяет увеличить надежность программы за счет уменьшения вероятности несанкционированного доступа к памяти из-за неправильного определения адресов.

Как альтернатива описанного выше подхода, в Объектном Паскале для работы с массивами переменной длины определен специальный тип – динамические массивы. Описание динамического массива:

Var имя_массива: Array of Array of…Array ofтип_элемента;

Ключевые слова Array of записываются в описании столько раз, сколько индексов у массива. По существу объявленноеимя_массиваявляется указателем на массив. Начальное значение индексов динамического массива равно нулю.

Выделение памяти под массив осуществляется с помощью процедуры SetLength(см. также §3.1.2). Вызов этой процедуры имеет вид:

SetLength(имя_массива, размер1, размер2,…,размерM).

В скобках указываются размеры массива по первым M (не обязательно всем) индексам.

Пример 1. В приведенном ниже фрагменте программы выделяется память под вещественный одномерный массив a размером n и под целочисленную матрицу b из n строк и m столбцов. Значения n и m предварительно задаются вводом.

Var a:Array of Real; b:Array of Array of integer; n,m:integer;

Begin

Readln(n,m);

SetLength(a,n); SetLength(b,n,m);…

Для работы с массивами (необязательно динамическими) также используются функции:

Length(a)– возвращает размер массиваaпо первому индексу;

Low(a)– возвращает наименьший номер компонента массиваa (для динамических массивов ноль);

High(a)– возвращает наибольший номер компонента массиваa;

SizeOf(a)–возвращает число байтов памяти, занимаемых массивомa.

Для освобождения памяти, отведенной под динамический массив, достаточно присвоить его имени значение nil.

Пример 2. В приведенной ниже программе осуществляется ввод и вывод динамической матрицы, размеры которой задаются вводом.

program Primer2;

Var a:Array of Array of real; n,m,i,j:integer; {n,m – размеры матрицы}

{i,j – счетчики строк и столбцов}

Begin

writeln(’Input count of rows’); readln(n);

writeln(’Input count of columns’); readln(m);

SetLength(a,n); {отводится память под указатели на строки}

writeln(’Input array ’, n, ’*’,m);

for i:=0 to High(a) do {High(a)=n-1)}

begin

Setlength(a[i],m); { отводится память под элементы строки}

for j:=0 to High(a[i]) do {High(a[i]=m-1}

read(a[i,j]);

end; readln; {закончен ввод динамического массива}

// обработка матрицы – заглушка

writeln(’output of dynamic array’);

for i:=0 to High(a) do

begin

for j:=0 to High(a[i]) do

write (a[i,j]:7:2); writeln;

a[i]:=nil; {освобождение памяти из-под строки}

end;

a:=nil;{ освобождение памяти из-под указателей на строки }

readln

End.