
- •Билет 20 Объявление типов и использование имен типов для описания данных.
- •Процедуры вывода write и writeln. Управление форматом вывода числовых и текстовых величин.
- •Билет 21
- •Особенности использования массивов в качестве параметров процедур и функций.
- •Билет 22 Открытые и динамические массивы. Запрос и освобождение памяти во время работы программы.
- •Цикл repeat.
- •Билет 23 Раздел констант.
- •Типизированные "константы" в Паскале.
- •Присвоение переменным начальных значений.
- •Специфика Object Pascal.
- •Процедуры ввода read, readln
- •Билет 25 Управление форматом выводимых данных с помощью. Процедуры Format
- •Операторы цикла. Назначение операторов break и continue.
- •Билет 26 Управление файлами в стиле Windows. Управление файлами в стиле Windows
- •В чем разница между выборкой данных из текстового файла по операторам read и readln.
Билет 22 Открытые и динамические массивы. Запрос и освобождение памяти во время работы программы.
Динамические массивы
Free Pascal так же, как и Object Pascal, поддерживает массивы двух категорий. Первую из них составляют традиционные массивы Паскаля, при объявлении которых в явном или косвенном виде указываются конкретные границы изменения каждого индекса:
const
k=5;
q=6;
type
mat_q_k = array [1..q,1..k] of integer;
var
sa1 : array [3..10] of byte; // явное задание границ
sa2 : mat_q_k; // косвенное задание границ
В ряде алгоритмических языков приняты соглашения о минимальном значении каждого индекса — в C и C++ индексы отсчитываются от 0, в Фортране — от 1, в Бейсике минимальной границей индекса можно управлять (оператор OPTION BASE). Паскаль допускает в качестве минимальных индексов любые значения порядковых данных. И ими могут быть не только числа, но и, например, символы:
var
ch:array ['A'..'Z'] of integer;
str:string;
...
begin
...
inc(ch[str[j]]);
...
Приведенный фрагмент наиболее простым способом позволяет подсчитать частоту появления тех или иных букв в обрабатываемом тексте.
Существует несколько вариантов для объявления многомерных массивов. Например, целочисленная матрица sa2, содержащая q строк и k столбцов может быть включена в текст программы еще одним из следующих описаний:
var
sa2:array [1..q,1..k] of integer;
или
var
sa2:array [1..q][1..k] of integer;
или
var
sa2:array [1..q] of array [1..k] of integer;
В языке Free Pascal для обозначения традиционных массивов используется термин "статические массивы", хотя он не совсем точно описывает логику выделения памяти для их хранения. Дело в том, что традиционные массивы в зависимости от места их определения делятся на глобальные и локальные. Глобальные массивы описываются в одном из разделов объявлений головной программы. В отличие от них описания локальных массивов встречаются внутри функций или подпрограмм. Для хранения глобальных массивов компилятор выделяет память перед началом работы программы и чистит ее (числовые массивы заполняются нулями, а строковые — пустыми строками). Глобальные массивы хранятся в памяти до окончания работы программы и доступны в любой программной единице (функции или подпрограмме). В отличие от этого память для хранения локальных массивов выделяется во время работы программы в тот момент, когда вызывается та или иная программная единица. Эта память не чистится и доступна только в рамках той программной единицы, где она объявлена. При возврате из программной единицы память из-под локальных массивов освобождается. Поэтому локальные массивы появляются в оперативной памяти динамически, и термин "статический" в такой ситуации не очень удачен.
Вторую категорию составляют действительно динамические массивы, объявление которых не содержат указания о границах изменения индексов:
var
da1 : array of integer; {одномерный массив}
da2 : array of array of integer; {двумерный массив}
Так как объявление динамического массива не сопровождается указанием о длине, то компилятор выделяет для каждого динамического массива (глобального или локального) по 4 байта. В них хранится указатель на начало значений элементов динамического массива. В начальный момент значения всех таких указателей равны 0, что соответствует "пустым" динамическим массивам (ситуация напоминает стратегию распределения памяти под строки типа AnsiString).
Фактическое выделение памяти под динамические массивы производится только во время работы программы путем вызова процедуры SetLength (дословно — установить длину):
SetLength(da1,100);
Такое обращение эквивалентно "статическому" описанию вида:
da1 : array [0..99] of integer;
Индексы динамических массивов всегда отсчитываются от 0, поэтому в обращении к процедуре SetLength кроме имени динамического массива задается количество элементов. Память, впервые выделяемая динамическому массиву, всегда чистится.
Во время работы программы к процедуре SetLength можно обращаться много раз. Если при очередном обращении новая длина больше предыдущей, то значения ранее вычисленных элементов сохраняются, а всем добавляемым элементам присваиваются нулевые значения. Если новая длина динамического массива меньше текущей, то сохраняются значения начальных элементов, "лишние" элементы будут безвозвратно потеряны.
Для выделения памяти под двумерный динамический массив к процедуре SetLength обращаются с тремя параметрами, задавая количество строк и количество столбцов:
SetLength(da2,4,6);
Такое обращение эквивалентно "статическому" описанию вида:
da2 : array [0..3,0..5] of integer;
Если динамический массив был объявлен в процедуре или функции, то он является локальным и после выхода из программной единицы память, занимаемая значениями элементов массива, освобождается.
К дополнительным средствам досрочного возврата памяти, занятой элементами динамического массива, относятся следующие способы:
da1 := Nil; {прямая засылка нуля в указатель}
da2 := Nil;
или
SetLength(da1,0); {косвенная засылка нуля в указатель}
SetLength(da2,0);
или
Finalize(da1); {финальное освобождение ресурсов}
Finalize(da2);
Открытые массивы
При описании открытого массива (в разделе type или var) указывается тип элементов, из которых он состоит (например, real, char и др.), но не указываются границы индексов. Например:
mas1: array of real;
mas2: array of integer;
В результате получаются как бы безразмерные массивы. Их размер может задаваться и меняться в программе при ее выполнении. Это так называемое динамическое распределение памяти, а переменные открытых массивов представляют собой ничто иное, как указатели на динамически выделяемую область памяти. Т.е. в переменных открытых массивов будут содержаться адреса начала массива, а не сам массив.
Особенностью открытых массивов является то, что их индексы всегда начинаются с нуля (а не с единицы, которая чаще всего используется для обычных массивов).
Чтобы в программе выделить память под открытый массив, следует воспользоваться процедурой setlength, которая принимает два фактических параметра – имя открытого массива и устанавливаемое количество элементов в нем. В результате работы setlength в памяти выделяется столько байт, сколько необходимо для хранения n-го количества элементов определенного типа. Так, если массив ранее описан как real и задано 5 элементов, то процедура setlength выделит под него 40 байт, т.к. для хранения каждого числа типа real требуется 8 байт памяти (хотя не обязательно 8, это может зависеть от компилятора).
Функция high принимает в качестве параметра имя массива и возвращает индексный номер последнего элемента массива. Например, выделяется память под десять элементов открытого массива; значит, индекс последнего будет равен 9 (т.к. индексация начинается с 0), что и вернет функция high.
Чтобы освободить, выделенную под массив память, используется оператор nil.
Обычно открытые массивы используются для передачи в подпрограмму массивов переменных размеров. Это позволяет с помощью одной и той же подпрограммы обрабатывать массивы произвольной длины. Без использования открытых массивов пришлось бы для каждого массива иной длины писать собственную подпрограмму.
Рассмотрите программу ниже и запустите ее на выполнение. Вам станет более понятно описанное выше.
Примечание. Функция sizeof возвращает количество памяти (в байтах), отведенное под переменную.
var
a: array[1..10] of real;
b: array of real;
i, n: integer;
sum: integer;
begin
writeln('Переменная a занимает ', sizeof(a),' байт памяти.');
writeln('Переменная b занимает ', sizeof(b),' байт памяти.');
write(' : ');
readln(n);
setlength(b,n);
writeln('Индекс последнего элемента массива ', high(b));
sum := 0;
for i:=0 to high(b) do begin
sum := sum + sizeof(b[i])
end;
writeln('Массив b занимает в памяти ', sum, ' байт(а);');
writeln('но переменная b по-прежнему ', sizeof(b),'.');
b := nil;
sum := 0;
for i:=0 to high(b) do
sum := sum + sizeof(b[i]);
writeln('Сейчас массив b занимает в памяти ', sum, ' байт,');
writeln('т.к. память была освобождена с помощью nil.');
readln
end.
Память
putimage(x,y,содержимое по адресу uk,pr) выводит в заданное место экрана копию фрагмента изображения, ранее помещенную в память
getimage(x1,y1,x2,y2,содержимое по адресу uk) помещает в память копию прямоугольного фрагмента изображения
memavail функция, возвращающая всю свободную динамическую память (тип longint)
maxavail функция, возвращающая максимальный непрерывный свободный участок в heape памяти (тип longint)
addr(переменная) функция, которая указателю присвоит адрес переменной
freemem(указатель) процедура, освобождающая n областей памяти
getmem(указатель) процедура, по которой указатель получает значение и по этому адресу выделяется не одна область памяти (new), a n областей
dispose(указатель) процедура, по которой память, выделенная new, освобождается
new(указатель) процедура, по которой указатель получает в качестве значения адрес в динамической памяти и по этому адресу выделяет в соответствии с типом нужное количество байт
grapherrormsg(код) возвращает значение типа string, в котором по указанному коду ошибки дается соответствующее текстовое сообщение