Приведем вначале неполное решение задачи, выводящее все необходимые данные, кроме указателя на последний элемент:
uses PT4;
var
p1: PNode;
n: integer;
begin
Task('Dynamic2');
read(p1);
n := 0;
while p1 <> nil do
begin
write(p1^.Data);
n := n + 1;
p1 := p1^.Next;
end;
write(n);
end.
После запуска программы можно убедиться, что все числовые результирующие данные найдены правильно, однако из-за того, что не выведен указатель на последний элемент, решение признано ошибочным с диагностикой Выведены не все результирующие данные":
Добавим в конец программы оператор
write(p1);
После запуска нового варианта программы все требуемые данные будут выведены, однако результирующее значение указателя будет равно nil. Это связано с тем, что после завершения цикла while в переменной p1 содержится нулевой указатель, а не указатель на последний элемент динамической структуры:
Для того чтобы получить правильное решение, опишем вспомогательную переменную p2, в которой будем сохранять адрес элемента, предшествующего элементу с адресом p1. После завершения цикла while в этой переменной будет храниться адрес последнего элемента динамической структуры:
uses PT4;
var
p1,p2: PNode;
n: integer;
begin
Task('Dynamic2');
read(p1);
n := 0;
while p1 <> nil do
begin
write(p1^.Data);
n := n + 1;
p2 := p1; { сохраняем адрес текущего элемента }
p1 := p1^.Next; { и переходим к следующему элементу }
end;
write(n, p2);
end.
Запустив эту программу три раза, мы получим сообщение Задание выполнено!":
Знакомство с заданием
Рассмотрим простейшее задание, связанное с добавлением элемента к динамической структуре-стеку: Dynamic3.
При ознакомительном запуске этого задания мы обнаружим новое обозначение в тексте, описывающем результирующий стек, а именно, точки, обрамляющие первый элемент стека:
Точки обозначают элементы динамической структуры, память для которых должна быть выделена программой учащегося (в отличие от тех элементов, которые размещаются в памяти самим задачником).
Что произойдет, если динамическая структура будет создана с ошибками? Для того чтобы это выяснить, вернем в программе, решающей задание Dynamic3, указатель на прежнюю вершину стека, не добавляя к ней новый элемент:
uses PT4;
var
d: integer;
p1: PNode;
begin
Task('Dynamic3');
read(d, p1);
write(p1);
end.
После запуска данной программы окно задачника примет вид:
Скобки вокруг каждого элемента результирующего стека означают, что эти элементы созданы самим задачником, но располагаются не на тех позициях, на которых они должны находиться при правильном решении. Действительно, тот элемент, который в решении является первым, должен (после добавления нового элемента) оказаться вторым и т. д. Итак, наличие скобок в тексте результирующей динамической структуры означает, что ее элементы располагаются не в том порядке, который требуется.
Для получения правильного решения задания Dynamic3 необходимо явно выделить память для нового элемента, используя процедуру New, и заполнить поля этого элемента, связав его с текущей вершиной стека (в результате сам этот элемент станет новой вершиной, адрес которой и следует вывести):
uses PT4;
var
d: integer;
p1, p2: PNode;
begin
Task('Dynamic3');
read(d, p1);
New(p2);
p2^.Data := D;
p2^.Next := p1;
write(p2);
end.
Приведем вид окна задачника при первом запуске этой программы:
Знакомство с заданием
Рассмотрим простейшее задание на удаление элемента из динамической структуры -- Dynamic5. В нем требуется удалить из стека вершину и вернуть указатель на новую вершину, то есть на элемент, расположенный непосредственно за удаленным.
Особенность заданий на удаление элементов из динамических структур заключается в том, что удаляемый элемент необходимо не только отсоединить" от исходной динамической структуры, но и полностью "уничтожить", то есть освободить память, занимаемую этим элементом.
Для того чтобы напомнить учащемуся о необходимости уничтожения некоторых элементов исходной динамической структуры, эти элементы выделяются на экране синим цветом меньшей яркости, чем обычные элементы (на рисунке таким способом выделен элемент 15):
Вначале приведем неправильный вариант решения, в котором не освобождается память, занимаемая удаленным из стека элементом:
uses PT4;
var p1: PNode;
begin
Task('Dynamic5');
read(p1);
write(p1^.Data, p1^.Next);
end.
Несмотря на то что все результирующие данные будут совпадать с контрольными (то есть текст в разделах Полученные результаты" и "Пример верного решения" будет одинаковым), на информационной панели появится сообщение об ошибке "Не освобождена динамическая память", а в разделе исходных данных будет выделен красным цветом тот элемент, который требовалось удалить:
Для получения правильного решения достаточно добавить в конец программы оператор вызова процедуры Dispose, освобождающий память, на которую указывает указатель p1:
uses PT4;
var p1: PNode;
begin
Task('Dynamic5');
read(p1);