русс | укр

Языки программирования

ПаскальСиАссемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование

Все о программировании


Linux Unix Алгоритмические языки Аналоговые и гибридные вычислительные устройства Архитектура микроконтроллеров Введение в разработку распределенных информационных систем Введение в численные методы Дискретная математика Информационное обслуживание пользователей Информация и моделирование в управлении производством Компьютерная графика Математическое и компьютерное моделирование Моделирование Нейрокомпьютеры Проектирование программ диагностики компьютерных систем и сетей Проектирование системных программ Системы счисления Теория статистики Теория оптимизации Уроки AutoCAD 3D Уроки базы данных Access Уроки Orcad Цифровые автоматы Шпаргалки по компьютеру Шпаргалки по программированию Экспертные системы Элементы теории информации

Работа с динамическими переменными


Дата добавления: 2015-07-23; просмотров: 676; Нарушение авторских прав


Доступ, то есть обращение к динамическим переменным, возможен по двум схемам. Рассмотрим ситуацию, возникшую после присваивания:

p1:=@i;

Первый вариант очевиден:

i:=i+2;

Но, хотя на i ссылается указатель, переменная описана как статическая.

Для реализации косвенного доступа к переменной через указатель используется разыменование. То есть, чтобы по указателю получить доступ к переменной, необходимо после указателя поставить знак «^». Так, запись р1^ означает: «переменная, на которую ссылается р1». Поэтому операторы

i:=i+2 и p1^:=p1^+2

полностью эквивалентны. Разыменование имеет тип, совпадающий с базовым типом, в частности p1^ является переменной целого типа (по описанию выше).

Разыменование допустимо для любых ссылочных типов, например, возможны следующие конструкции:

j:=pp1^^;

f:=h.l^.g^.p;

При разыменовании может возникнуть некорректная ситуация, хотя и не приводящая к аварийному завершению, но дающая обычно неверное значение результата (это трудно обнаруживаемая ошибка). Это разыменование указателя со значением nil. За этим необходимо внимательно следить при составлении и отладке программы.

 

Основные действия над динамическими переменными — это их создание и уничтожение. Первое реализуется стандартной процедурой

New (<указатель>)

При выполнении этой процедуры происходят следующие действия:

1. В динамической области памяти отводится место для переменной по размеру базового типа указателя.

2. Указателю присваивается адрес этой переменной.

Пример.

Var I,J: ^integer; { определяем два указателя на целую переменную }

NEW (J); { выделяем память для целой переменной и присваиваем ее адрес указателю }

I:=J; { I и J указывают на одну и ту же переменную (J:=I —запрещено) }

J^:=5; { запись числа в выделенную память }

I^:=6; { стало и J^=6 }



I:=NIL; { I ни на что не указывает }

J:=NIL; { доступа к переменной больше нет, она не нужна }

При использовании динамических переменных происходит постоянный процесс изменения указателей. При этом некоторые переменные могут оказаться ненужными, ссылки на них уничтожаются. Но они занимают память, которую ни для каких других целей использовать нельзя, то есть образуют «мусор». Таким образом может возникнуть ситуация, что памяти более чем достаточно, но для размещения новой переменной в динамической области памяти, называемой «кучей», нет места. В этом случае значение указателя из параметра не изменится, но никаких сообщений выдано не будет, что может привести к непредсказуемым последствиям. Для повышения надежности программы следует проверять текущее состояние «кучи» перед каждым созданием новой переменной. Это можно сделать с помощью стандартной функции MaxAvail без параметров, возвращающей максимальный размер непрерывного участка свободной памяти, пригодного для размещения переменной. Например, для 4-байтовой переменной типа longint:

Var p:longint;

Begin

...

If MaxAvail >=4 then

New(p)

else

Writeln (‘Переполнение памяти’);

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

If MaxAvail >= SizeOf (TypeDat) then ...

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

Dispose (<указатель>);

Работа с динамическими переменными требует большой аккуратности, иначе «засоре­ние» памяти ненужными переменными может привести к быстрому ее исчерпанию. Трудно обнаруживаемые ошибки могут возникать при использовании динамических переменных в подпрограммах: при выходе из них локальные ссылки на вновь созданные переменные теряются. Поэтому нужно придерживаться правила: при выходе из подпрограммы или освобождается память от вновь созданных в ней переменных, или ссылки сохраняются через параметры.

Пример двухсвязанного циклического списка

Определим функции при работе со списком с пояснениями, представленными на рис. 7.1:

0 - просмотр влево (подпрограмма PRL);

1 - просмотр вправо (подпрограмма PRR);

2 - удаление (подпрограмма DEL);

3 - вставка (подпрограмма BCT);

4 - конец работы.

При проходе первого элемента переводится строка.

Рис. 7.1. Операции с узлами двухсвязанного циклического списка

Program SW_Spisok2;

{ Демонстрационный пример использования динамических переменных: двухсвязанный циклический список }

Uses crt;

Type P=^dat;

dat=Record

INF:char; { любой нужный тип элемента списка }

L,R:P;

end;

Var Point, { указатель на начало кольца }

lef,rig,n:P;

ch:char;

 

Procedure PRL; { процедура сдвига влево }

Begin

rig:=lef;

lef:=rig^.l; { сдвиг указателей }

Write(lef^.inf);{ вывод информационного поля }

If lef=Point then

Writeln; { начало кольца }

end;

 

Procedure PRR; { процедура сдвига вправо }

Begin

lef:=rig;

rig:=lef^.r;

Write(lef^.inf);

If lef=Point then

Writeln;

end;

 

Procedure DEL; { процедура удаления }

Begin

If lef^.l=lef^.r then{ не менее 2х элементов }

Writeln('Осталось два элемента')

else

If lef=Point then

Writeln('Начало списка')

else

Begin

rig^.l:=lef^.l; { изменение указателей }

lef^.l^.R:=lef^.r;

Dispose(lef); { возвращение памяти }

lef:=Rig^.l;

end;

end;

 

Procedure BCT; { процедура вставки }

Begin

ch:=ReadKey; Write(ch);

NEW(n);

n^.inf:=ch;

n^.l:=lef; { связи из нового узла }

n^.r:=rig;

rig^.l:=n; { указание на новый узел }

lef^.r:=n;

rig:=n;

writeln;

end;

 

Begin { непосредственно сама программа }

ch:=ReadKey; Write(ch);

NEW(rig);

rig^.inf:=ch; { первый правый узел }

ch:=ReadKey; Write(ch);

NEW(lef);

lef^.inf:=ch; { первый левый узел }

rig^.l:=lef;

rig^.r:=lef;

lef^.l:=rig;

lef^.r:=rig;

Point:=lef; { начало кольца }

Repeat

Ch:=ReadKey;

Case ch of { анализируем введенную команду }

'0': PRL;

'1': PRR;

'2': DEL;

'3': BCT;

'4': Writeln('Конец')

else

Writeln('Неверный ввод')

end;

Until ch='4'; { пока не встретим команду «конец» }

end.



<== предыдущая лекция | следующая лекция ==>
Указатели | Указатели без типа


Карта сайта Карта сайта укр


Уроки php mysql Программирование

Онлайн система счисления Калькулятор онлайн обычный Инженерный калькулятор онлайн Замена русских букв на английские для вебмастеров Замена русских букв на английские

Аппаратное и программное обеспечение Графика и компьютерная сфера Интегрированная геоинформационная система Интернет Компьютер Комплектующие компьютера Лекции Методы и средства измерений неэлектрических величин Обслуживание компьютерных и периферийных устройств Операционные системы Параллельное программирование Проектирование электронных средств Периферийные устройства Полезные ресурсы для программистов Программы для программистов Статьи для программистов Cтруктура и организация данных


 


Не нашли то, что искали? Google вам в помощь!

 
 

© life-prog.ru При использовании материалов прямая ссылка на сайт обязательна.

Генерация страницы за: 0.323 сек.