- •Понятие о динамических данных. Динамические массивы.
- •Данные, используемые паскаль-программой
- •Динамическое распределение памяти используется:
- •Что такое указатель?
- •Указатели в Объектном Паскале
- •Указатели в Объектном Паскале (продолжение)
- •Операторы (процедуры) для распределения
- •Почему неудобны статические (или локальные) массивы?
- •Описание динамического массива
- •Работа с динамическими массивами
- •Пример3
- •Пример 4
- •Пример 5
- •Открытые массивы - формальные параметры-массивы без указания границ
- •Пример 6. Вычисление максимальных значений элементов двух одномерных массивов. Подпрограммы используют открытые массивы.
Понятие о динамических данных. Динамические массивы.
лекция №17
Данные, используемые паскаль-программой
Статические
(глобальные):
•описываются в разделах (переменных и констант) программы;
•распределяются в памяти на этапе компиляции и существуют все время выполнения программы;
•место в памяти – статический сегмент;
•доступны в любой точке программы, за исключением подпрограмм, имеющих локальные переменные с тем же именем.
Локальные:
•описываются в разделах (переменных и констант) подпрограммы;
•распределяются в памяти на этапе выполнения (при каждом вызове подпрограммы) и освобождают память при завершении работы программы;
•место в памяти – стэк;
•доступны в блоке подпрограммы.
Динамические:
•описываются не данные, а их адреса (указатели);
•распределяются и уничтожаются в памяти на этапе выполнения программы по специальным командам;
•место в памяти –
динамическая память (англ. куча – heap);
•время жизни и область действия указателей определяется как для обычных (локальных или глобальных) переменных
Динамическое распределение памяти используется:
•когда статической памяти и стека подпрограмм не хватает для решения задачи;
•когда характер задачи требует динамического распределения (данные поступают порциями в процессе выполнения программы, например, в режиме реального времени).
Что такое указатель?
• Указатель - абстрактное обобщение адреса.
•Указатель не определяют как переменную, принимающую значения на множестве адресов, потому что значение адреса зависит от конкретной ЭВМ и условий, в которых происходит работа компилятора.
•Указатели используются при работе с динамической памятью.
•Тип указатель имеется во всех универсальных языках программирования.
Указатели в Объектном Паскале
Типированные |
|
Нетипированные |
Описание типированного указателя:
VAR имя_типированного_указателя: ^тип_содержимого_ячейки;
В качестве типа содержимого ячейки (базового типа) может быть использован любой стандартный тип или имя нестандартного типа.
Описание нетипированного указателя:
имя_нетипированного_указателя: pointer;
Операция @ - взятие адреса переменной;
@A – адрес переменной A (или адрес первого байта массива или
структуры A).
Операция ^ - взятие содержимого;
b ^ – содержимое ячейки с адресом b (сравните положение значка ^ с тем, что используется при объявлении указателей).
b ^ можно использовать точно так же, как и переменную базового для указателя b типа.
Указатели в Объектном Паскале (продолжение)
Статический сегмент памяти
Пример. |
|
С |
|
||
Var C: ^integer; i:integer; |
|
|
Begin C:=@i; {в ячейку С записан |
|
|
адрес ячейки i} |
|
|
C^:=1; {в ячейку с |
|
|
адресом С записано значение 1} |
|
i |
… |
|
|
|
|
|
End. |
|
|
|
|
|
C:=@i {после этого оператора i ^C}
C^:=1эквивалентно i:=1
Встроенная константа 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.
Мы будем работать только с специальным видом динамических переменных – динамическими массивами!
Почему неудобны статические (или локальные) массивы?
•Основной трудностью работы со статическими массивами является обязательность указания количества их элементов при объявлении. В любом алгоритмическом языке, требующим компиляции (в частности, в Паскале),
границами индексов массива в инструкции array могут быть только константы.
•Выход – использование динамических массивов.
Описание динамического массива
Var имя_массива: Array of Array of…Array of тип_элемента;
Ключевые слова Array of записываются в описании столько раз, сколько индексов у массива (т. е. какова его размерность).
По существу объявленное имя_массива является указателем на массив.
Работа с динамическими массивами
1.Распределение памяти под массив: с помощью процедуры SetLength:
SetLength(имя_массива, размер1, размер2, …,размерM).
В скобках указываются размеры массива по первым M (не обязательно всем) индексам.
2.Работа как со статическим массивом. Элементы динамического массива нумеруются с нуля.
3.Освобождение памяти:
•имя_массива:=nil ;
•установление нулевой длины с помощью SetLength.