
- •Понятие динамической памяти
- •2 Указатель и его назначение
- •2.1 Создание динамической переменной. Процедура new. Ссылки
- •2.2 Связные списки. Константа nil
- •2.3 Нетипизированные указатели
- •Процедуры и функции для работы с динамическими данными
- •Динамически связанные данные
- •4.1 Понятие и характеристики информационных структур
- •4.2 Очереди. Стеки
- •4.3 Списки
2.2 Связные списки. Константа nil
Указатель можно заставить работать еще более гибким и эффективным образом. Для этого его нужно включить в состав записи, например, так:
Type StudPtr = ^StudRec;
StudRec = record
name :string[20];
age :integer;
nextStud:StudPtr
end;
Var StudList:StudPtr;
Первые две строки приведенного примера заслуживают особого внимания. Вызывает удивление тот факт, что в определении типа StudPtr фигурирует тип StudRec, определяемый позже. Это исключение из общего правила Паскаля, утверждающего, что нельзя использовать объект прежде, чем он будет объявлен.
Чего мы достигаем, поместив указатель внутрь записи? Теперь нет необходимости в массиве указателей.
При самом первом обращении к процедуре New мы передаем ей указатель StudList. Созданная при этом запись среди прочих полей содержит указатель NextStud, который можно затем передать процедуре New, чтобы она создала еще одну, вторую по счету запись:
New(StudList^.NextStud)
Но аналогичный указатель есть и в этой записи; его полное имя - StudList^.NextStud^.NextStud^. Будучи употреблено в качестве параметра обращения к New, оно позволяет получить следующую (третью) запись. Действуя подобным образом, мы постепенно выстраиваем некую цепочку записей, в которой каждая запись указывает на следующую за ней. Такого рода структура данных называется связным списком. При проходе по такому списку элемент, стоящий в самом конце (то есть не имеющий за собой следующего), должен содержать в своем поле NextStud некоторое специальное значение, ни на что не указывающее. В Паскале это значение изображается как стандартная символическая константа nil (ничего).
Правомерно, например, присваивание
Var aPtr: ^integer;
..............
aPtr:=nil;
Стандартная константа nil предназначена для изображения пустого значения указателя, то есть такого, при котором указатель не ссылается ни на какую область памяти.
В программировании очень важным является понятие списка. Список – это последовательность элементов (Е1, Е2, …, Еn), для которых задан порядок следования. Порядок следования может задаваться как явно, так и неявно.
При неявном порядке следования элементов их располагают в смежных ячейках памяти. Например, массив может рассматриваться как список с неявным заданием порядка следования элементов.
При явном задании порядка следования каждый элемент списка содержит указатель, определяющий место нахождения следующего элемента списка. В этом случае элементы отображают в виде списка такого вида:
Такие списки называют линейными или связными.
2.3 Нетипизированные указатели
Все описанные выше указатели связаны с конкретными типами данных. Паскаль - строго типизированный язык; поэтому присваивать указателю значение другого указателя, относящегося к другому типу данных нельзя. Но это ограничивает возможности программиста. Обойти такое ограничение позволяет использование нетипизированных указателей. Для объявления переменной нетипизированным указателем нужно употреблять ключевое слово Pointer. Значением нетипизированного указателя может являться либо адрес, либо Nil.
Нетипизированному указателю может быть присвоено значение любого типизированного указателя, и наоборот. Рассмотрим пример.
Program Ex29;
Const p1:^byte=nil; p2:^string=nil; p3:pointer=nil;
Begin
New(p2);
p2^:='ab'; p3:=p2; p1:=p3;
writeln(p1^) End.
В результате выполнения этой программы указатели P1 и P2 будут ссылаться на одну и ту же область памяти, первоначально выделенную динамической переменной P2^. Поскольку прямо присвоить значение P1 значение P2 нельзя, пришлось использовать нетипизированный указатель P3. В результате своей работы программа выведет на экран длину символьной строки, которая равна 2.