программирование на паскале2. Учебное пособие по курсу Высокоуровневые методы информатики и программирования для студентов Гуманитарноприкладного института
Скачать 0.89 Mb.
|
Часть IV. Работа с динамическими массивами
Статическое распределение памяти происходит на этапе компиляции программы; это распределение не изменяется в процессе выполнения программы. Динамическое распределение памяти - это выделение и освобождение памяти в процессе выполнения программы. Данные, размещаемые в памяти компилятором, называются статическими, а распределяемые в ходе выполнения программы - динамическими. Распределение памяти под глобальные данные (объявленные в разделах программы – см. §2.4) является статическим. При распределении локальных данных подпрограмм имеет место элемент динамизма, так как оно происходит на этапе выполнения программы при вызове подпрограммы. Заметим, что распределение локальных данных не изменяется в процессе выполнения подпрограммы, а при завершении подпрограммы память освобождается. Обычно под динамическим распределением памяти понимается выделение и освобождение памяти в процессе выполнения программы с помощью специальных операторов динамического распределения памяти. Эти операторы используют тип данных указатель, предназначенный для хранения адреса области памяти. При динамическом распределении память берется из специальной области, называемой динамической памятью или кучей. Указатель определяется как абстрактное обобщение адреса (а не как переменную, принимающую значения на множестве адресов), потому что значение адреса зависит от конкретной ЭВМ и условий, в которых происходит работа компилятора. Тип указатель имеется во всех универсальных языках программирования. Динамическое распределение памяти используется в двух ситуациях:
Пример второй ситуации рассматривается в §4.3.
Указатели в рассматриваемых версиях Паскаля могут быть типированными или нетипированными. Типированные указатели хранят адрес ячейки данных заявленного типа, для нетипированных указателей тип содержимого не задается. Указатели описываются с помощью инструкций: имя_типированного_указателя: ^тип_содержимого_ячейки; имя_нетипированного_указателя: 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. |