Научная статья на тему 'ТЕСТИРОВАНИЕ ПРОГРАММ НА ЯЗЫКЕ ПАСКАЛЬ, ИСПОЛЬЗУЮЩИХ ДИНАМИЧЕСКУЮ ПАМЯТЬ'

ТЕСТИРОВАНИЕ ПРОГРАММ НА ЯЗЫКЕ ПАСКАЛЬ, ИСПОЛЬЗУЮЩИХ ДИНАМИЧЕСКУЮ ПАМЯТЬ Текст научной статьи по специальности «Компьютерные и информационные науки»

CC BY
206
11
i Надоели баннеры? Вы всегда можете отключить рекламу.
Ключевые слова
ЯЗЫК ПАСКАЛЬ / ТЕСТИРУЮЩИЕ ПРОГРАММЫ / ПРОГРАММИРОВАНИЕ / ИНФОРМАТИКА / ДИНАМИЧЕСКИЕ СТРУКТУРЫ ДАННЫХ / ДИНАМИЧЕСКАЯ ПАМЯТЬ / ЛИНЕЙНЫЕ СПИСКИ / ДВОИЧНЫЕ ДЕРЕВЬЯ

Аннотация научной статьи по компьютерным и информационным наукам, автор научной работы — Новиков М.Д.

Статья является продолжением серии статей, посвященных системе автоматического тестирования программ на Паскале, разрабатываемой на факультете вычислительной математики и кибернетики МГУ им. М.В. Ломоносова. В статье описываются особенности тестирования программ, использующих динамическую память и реализующих обработку сложных структур данных - списков и двоичных деревьев.

i Надоели баннеры? Вы всегда можете отключить рекламу.
iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.
i Надоели баннеры? Вы всегда можете отключить рекламу.

TESTING PROGRAMS IN PROGRAMMING LANGUAGE PASCAL THAT USE DYNAMIC MEMORY

This article continues the series of articles devoted to description of the automated program testing system that has been developing at the faculty of Computational mathematics and cybernetics of Moscow State University. Some peculiarities of testing Pascal programs using dynamic memory and processing linear lists and binary trees are described in the article.

Текст научной работы на тему «ТЕСТИРОВАНИЕ ПРОГРАММ НА ЯЗЫКЕ ПАСКАЛЬ, ИСПОЛЬЗУЮЩИХ ДИНАМИЧЕСКУЮ ПАМЯТЬ»

—— East European Scientific Journal #3(67), 2021 45

ФИЗИКО-МАТЕМАТИЧЕСКИЕ НАУКИ

УДК 004.42, 004.438

Новиков М.Д.

ТЕСТИРОВАНИЕ ПРОГРАММ НА ЯЗЫКЕ ПАСКАЛЬ, ИСПОЛЬЗУЮЩИХ ДИНАМИЧЕСКУЮ ПАМЯТЬ

Novikov M.D.

TESTING PROGRAMS IN PROGRAMMING LANGUAGE PASCAL THAT USE

DYNAMIC MEMORY

Аннотация. Статья является продолжением серии статей, посвященных системе автоматического тестирования программ на Паскале, разрабатываемой на факультете вычислительной математики и кибернетики МГУ им. М.В. Ломоносова. В статье описываются особенности тестирования программ, использующих динамическую память и реализующих обработку сложных структур данных - списков и двоичных деревьев.

Abstract. This article continues the series of articles devoted to description of the automated program testing system that has been developing at the faculty of Computational mathematics and cybernetics of Moscow State University. Some peculiarities of testing Pascal programs using dynamic memory and processing linear lists and binary trees are described in the article.

Ключевые слова: язык Паскаль, тестирующие программы, программирование, информатика, динамические структуры данных, динамическая память, линейные списки, двоичные деревья.

Key words: programming language Pascal, testing programs, programming, computer science, dynamic data structures, linear lists, binary trees.

Введение.

Система автоматического тестирования программ (далее - Система) разрабатывается на факультете ВМК МГУ с 2017 года и предназначена для проверки правильности работы программ на языке Паскаль, составляемых студентами первого курса факультета ВМК в рамках практикума по программированию на ЭВМ. За основу взяты задачи из двух учебных пособий: 1) из учебного пособия [1], в котором собрано несколько сотен задач на различные темы, начиная с таких простых тем как 'Условный оператор' и 'Операторы цикла' и кончая сложными темами 'Списки' и 'Деревья'; 2) из учебного пособия [2], которое содержит различные сложные задания по практикуму на ЭВМ. Об особенностях написания и тестирования программ из глав 3 - 15 пособия [1] рассказывается в работах [3], [4] и [5]. Данная же статья посвящена тестированию программ, реализующих обработку списков и деревьев (главы 16 и 17 пособия [1], задание 2 из пособия [2]).

Особенности задач на обработку списков и деревьев.

Задачи на обработку сложных структур данных - списков и деревьев - предполагают использование динамической памяти ЭВМ. Возникает проблема корректного использования этой памяти, т.е. недопущение таких последствий ее неправильного использования, как появление висячих ссылок и утечку памяти в процессе работы программы. Например, программа, строящая список из N элементов, должна обратиться к процедуре New выделения памяти под один элемент списка ровно N раз. Аналогично

программа, удаляющая из списка какие-либо элементы, должна обратиться к процедуре освобождения памяти Dispose столько раз, сколько элементов списка удаляется. В студенческих программах данное требование часто не соблюдается, а именно: создается больше динамических элементов, чем требуется, и не все динамические элементы удаляются. Такие ошибки не фиксируются в процессе выполнения программы, т.е., несмотря на неправильное использование динамической памяти, выдается верный ответ.

Замечание. Если, наоборот, создается меньше динамических элементов, чем требуется или удаляются лишние элементы, то это обычно приводит к неверному результату или возникает ошибка периода выполнения Runtime Error.

Реализация проверки правильности использования динамической памяти.

Данные для представления линейных списков и двоичных деревьев могут быть описаны следующим образом ([1], с. 155, 171).

Список:

type Tlist=ATelem; Telem=record data:Tdata; next: Tlist end;

Дерево:

type Ttree=ATelem; Telem=record data:Tdata; left, right: Ttree end;

В качестве типа Tdata могут быть использованы любые типы данных: real, integer и т.д.

Приведем процедуру, создающую список из N элементов (N>0 - константа):

procedure create_list(var L:Tlist);

46 East European Scientific Journal #3(67), 2021 var r:real; i:integer; p:Tlist; begin

for i:=1 to n do begin

read(r);

if i=1 then begin new(L); LA.data:=r; LA.next:=nil; p:=L end

else begin new(pA.next); p:=pA.next; pA.data:=r; pA.next:=nil end; end; end;

Процедура New вызывается при работе процедуры ровно N раз.

Приведем далее пример процедуры, неправильно обрабатывающей список. Рассмотрим задачу 16.29 к) из [1], в которой требуется составить процедуру, оставляющую в заданном списке из группы подряд стоящих одинаковых элементов только один элемент.

procedure remove_equal(L:Tlist);

var p,r:Tlist;

begin

if (L=nil)or(LA.next=nil)then exit;

p:=L;

while pA.next<>nil do begin

r:=pA.next;

if pA.data=rA.data then begin pA.next:=rA.next end else p:=pA.next end; end;

В этой процедуре изменяются лишь ссылки на элементы списка, но элементы, ставшие ненужными, не удаляются. Тем не менее, процедура всегда выдает правильный результат.

Для корректировки процедуры достаточно вставить оператор Dispose(r) после изменения ссылки p:

procedure remove_equal(L:Tlist);

var p,r:Tlist;

begin

if (L=nil)or(LA.next=nil)then exit;

p:=L;

while pA.next<>nil do begin

r:=pA.next;

if pA.data=rA.data then begin pA.next:=rA.next; Dispose(r) end else p:=pA.next end; end;

Проблема состоит в том, чтобы на этапе выполнения тестируемой процедуры создания, обработки и удаления списка или дерева проверить количество вызовов процедур New и Dispose. В описываемой Системе это реализовано следующим образом.

Каждый вызов процедуры New(p) и Dispose(p) заключается в блок типа:

Begin inc(s); New(p)/Dispose(p); end;

(1)

где s - специальная глобальная переменная, описанная вне процедуры. По окончании работы

UB

вшам

процедуры проверяется, совпадает ли количество обращений к процедуре New или Dispose с требуемым.

В учебных пособиях [1] и [2] задачи на обработку списков и деревьев ставятся следующим образом.

1) Написать процедуру или функцию, обрабатывающую заданную динамическую структуру (требуется написать только подпрограмму без основного блока).

2) Написать полную программу, создающую и обрабатывающую список или дерево.

В случае 1) Система добавляет к тестируемой процедуре или функции основной блок, в котором создаются исходные данные для процедуры (функции) и одновременно подсчитывается требуемое количество обращений к процедурам New и Dispose при ее выполнении. Затем вызывается тестируемая процедура (функция) и по окончании ее работы проверяется количество вызовов процедур New и Dispose.

В случае 2) Система заключает тестируемую программу в процедуру; к тестируемой программе добавляются операторы подсчета количества вызовов процедур New и Dispose (1). Формируется также основной блок, из которого вызывается тестируемая программа.

Приведем программу (с комментариями), которая будет сформирована Системой для тестирования приведенной выше процедуры к задаче 16.29 к).

{Система всегда добавляет к любой тестируемой программе или подпрограмме директивы контроля операций ввода-вывода и значений ограниченных типов.} {$I+,R+}

{Имена дополнительных переменных, в которых подсчитывается количество обращений к функциям New и Dispose задаются случайным образом для предотвращения возможных коллизий. В данной программе имена обозначены как abcdef и xyzdef.}

var abcdef:integer;

{Добавляется описание типов данных, используемых тестируемой процедурой.} type Tlist=ATNode; TNode=record Data: real; next: Tlist end;

{ В тестируемой процедуре все обращения к функции Dispose(r) заменяются на операторы begin inc(abcdef); dispose(r) end;} procedure remove_equal(L:tlist); var p,r:tlist;

begin if(L=nil)or(LA.next=nil)then exit;

p:=L;

while pA.next<>nil do begin r:=pA.next;

if pA.data=rA.data then begin pA.next:=rA.next;

begin inc(abcdef);

dispose(r)end

end

else p:=pA.next end; end;

ив

вшэа

{Системой формируется основной блок. В нем строится список (число 1E20 означает конец ввода) и одновременно подсчитывается количество подряд стоящих одинаковых элементов (т.е. количество необходимых обращений к процедуре Dispose при их последующем удалении). После этого вызывается тестируемая процедура. По окончании выполнения тестируемой процедуры производится печать результирующего списка, его удаление и проверка правильности количества обращений к функции Dispose.}

var L,p:Tlist;

xyzdef:integer;

q,r:real;

begin

read(r);

if r=1E20 then L:=nil else begin new(L);

LA.next:=nil;

LA.data:=r;

p:=L;

end;

if L<>nil then repeat read(q); if q=1E20 then break;

new(pA.next);

p:=pA.next;

pA.data:=q;

pA.next:=nil;

if r=q then inc(xyzdef);

r:=q until r>=1E20;

remove_equal (L); IIВызов тестируемой процедуры

p:=L;

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.

while L<>nil do begin write(LA.data:1:3,' '); L:=LA.next end;

if abcdef<>xyzdef then write('Неверное количество обращений к процедуре Dispose'); L:=p;

while L<>nil do begin p:=lA.next;

dispose(L);

L:=p end;

end.

Рассмотрим теперь случай, когда надо тестировать полную программу, использующую динамическую память. Приведем программу с комментариями, которая будет сформирована Системой для тестирования такой полной программы.

{Случайным образом задаются имена дополнительных переменных, в которых подсчитывается количество обращений к функциям New и Dispose в процессе работы тестируемой программы}

var abcdtf1,abcdtf2:integer; {Тестируемая программа заключается в процедуру, имя которой также задается случайным образом}

East European Scientific Journal #3(67), 2021 47 procedure PPPPPP; {$I+,R+}

{Здесь расположена тестируемая программа, в которой каждое обращение к процедуре New и Dispose заменено на блок (1)}

{Основной блок, формируемый Системой} begin

abcdef1:=0; abcdef2:=0; PPPPPP;

{Так как тестируемая программная единица представляет собой полную программу в которой создается и обрабатывается список или дерево, то по окончании обработки данная динамическая структура должна быть удалена. Поэтому количество обращений к функциям New и Dispose должно совпадать.}

if abcdef1-abcdef2<>0 then write('HeBepHoe количество обращений к процедурам New и Dispose') end.

Заключение.

Данная методика проверки использования динамической памяти позволила быстро выявлять любые ошибки, связанные с неправильным использованием этой памяти при обработки таких сложных структур данных, как списки и деревья. Методика показала свою эффективность при тестировании студенческих программ.

Литература.

1. Пильщиков В. Н. Язык Паскаль. Упражнения и задачи. М.: Научный мир, 2003. 224 с.

2. Трифонов Н.П., Пильщиков В.Н. Задания практикума на ЭВМ (1 курс). М.: Издательский отдел факультета вычислительной математики и кибернетики МГУ им. М. В. Ломоносова, 2001, 32 с.

3. Новиков М.Д. Система автоматического тестирования программ, написанных на языке программирования Паскаль. Альманах современной науки и образования. Тамбов.: Изд-во Грамота, №6, 2017 г.

4. Новиков М.Д. Автоматизированный практикум по языку программирования Паскаль. Наука России: цели и задачи. Сборник статей по материалам XV международной научно-практической конференции. Екатеринбург, 10.10. 2019 г.

5. Новиков М.Д. Автоматическое тестирование программ на языке Паскаль. Тезисы докладов конференции памяти Николая Павловича Трифонова. М.: Макс Пресс, 2020, с.34-36.

i Надоели баннеры? Вы всегда можете отключить рекламу.