- •1. Теоретические сведения
- •2. Встроенный отладчик системы Delphi
- •Команды, соответствующие командам отладчика
- •3. Использование команд отладчика
- •4. Методика отладки программы
- •5. Некоторые замечания
- •6. Лабораторное задание
- •7. Порядок выполнения лабораторной работы
- •8. Требования к отчету
- •9. Контрольные вопросы
- •10. Ваpианты заданий
4. Методика отладки программы
Отладка программы сопровождается тестированием, т.е. выполнением программы с целью обнаружения ошибок. Тест - это специальный набор входных данных для проверки программы. Удачным считается тест, который обнаруживает еще не выявленную ошибку.
Для разработки тестов используются различные методы. Воспользуемся одним из них - методом анализа граничных значений. Согласно этому методу для построения тестов применяются следующие общие правила:
1) построить тесты для границ области значений входных данных и тесты с неправильными входными данными для ситуаций незначительного выхода за границы области. Например, если входная строка может содержать от 1 до 80 символов, то нужно написать тесты для 0, 1, 80 и 81 символа;
2) построить тесты для получения (вычисления) минимального и максимального результирующих значений, а также построить (если это возможно) тесты, вызывающие получение результатов, которые меньше минимально допустимых значений и больше максимально допустимых значений. Например, если программа подсчитывает количество пробелов во входной строке, содержащей не более 80 символов, то нужно написать тесты, для которых программа должна выдать в качестве результата числа 0, 1, 80;
3) если входные данные или результаты являются последовательностью значений, то построить тесты для проверки первого, среднего и последнего значений в этой последовательности. Например, если программа отыскивает самое длинное слово в строке, то нужно использовать тесты в виде строк, в которых самое длинное слово находится в начале, середине и конце строки;
4) если входные данные или результаты являются последовательностью с переменным количеством значений, то построить тесты для случаев, когда эта последовательность оказывается (а) пустой и (б) содержит максимально возможное количество значений. Например, если программа отображает на экране n-буквенные слова, содержащиеся в строке, то нужно написать тесты в виде (а) строки, в которой нет ни одного n-буквенного слова, и (б) строки, состоящей только из n-буквенных слов.
Отладим программу, которая должна суммировать определенное количество элементов массива, состоящего из 10 целых чисел, начиная с элемента с заданным номером (рис.1).
{ 1} Program SUM; {$R+ Включить контроль диапазона значений}
{ 2} Const
{ 3} SIZE = 10; { Количество элементов в массиве}
{ 4} Type NUMBER = 0..SIZE;{ Тип номеров и числа элементов }
{ 5} MAS = array [1..SIZE] of smallint;
{ 6} Var
{ 7} Arr : MAS; { Исходный массив }
{ 8} f, { Номер начального элемента в сумме }
{ 9} n : NUMBER; { Число элементов в сумме }
{10} Procedure getarr {--- Ввод массива }
{11} (M : MAS); { Вводимый массив }
{12} Var
{13} i : smallint; { Параметр цикла }
{14} begin { getarr }
{15} for i:=1 to SIZE do
{16} begin
{17} write('Введите ',i,'-й элемент: ');
{18} readln(M[i]);
{19} end;
{20} end; { getarr }
{21} Procedure putarr {--- Вывод массива}
{22} (M : MAS; { Выводимый массив}
{23} name : string); { Имя массива }
{24} Var
{25} i : smallint; { Параметр цикла }
{26} begin { putarr }
{27} for i:=1 to SIZE do
{28} write(name,i:1,'=',M[i],' ');
{29} writeln;
{30} end; { putarr }
{31} Function getsum {--- Вычисление суммы элементов }
{32} (M : MAS; { Исходный массив }
{33} n1, {Номер начального элемента в сумме}
{34} k : NUMBER { Число элементов в сумме}
{35} ) : smallint;
{36} Var
{37} i : smallint; { Параметр цикла }
{38} sum1 : smallint; { Сумма элементов }
{39} begin { getsum }
{40} for i:=1 to k do
{41} sum1 := sum1 + M[n1+i];
{42} end; { getsum }
{43} Begin { SUM }
{44} getarr(Arr);
{45} repeat
{46} putarr(Arr,'Arr');
{47} write('Hомеp начального элемента(0-выход): ');
{48} readln(f);
{49} if f>0 then
{50} begin
{51} write('Количество элементов: ');
{52} readln(n);
{53} if f+n<SIZE then
{54} writeln('Cумма элементов: ',getsum(Arr,f,n))
{55} else
{56} writeln('Выход за границы массива');
{57} write('Нажмите Enter'); readln;
{58} end;
{59} until f = 0;
{60} End. { SUM }
Рис.1. Отлаживаемая программа
Входными данными для программы служат 10 целых чисел (элементы массива), номер элемента, с которого начинается суммирование, и количество суммируемых элементов. Результатом выполнения программы является вычисленная сумма заданного количества элементов массива.
Для тестирования программы воспользуемся наборами данных, приведенными в табл.4. Прочерк в графе "Ожидаемый результат" означает семантическую ошибку, сопровождаемую сообщением "Range check error" (недопустимое значение переменной).
Таблица 4
Тесты для проверки программы SUM
Номер Теста |
Входные данные |
Ожидае- мый ре- зультат |
Номера правил для анализа граничных значений | ||
Arr |
f |
n | |||
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
1,1,1,1,1,1,1,1,1,1 1,1,1,1,1,1,1,1,1,1 1,1,1,1,1,1,1,1,1,1 1,1,1,1,1,1,1,1,1,1 1,1,1,1,1,1,1,1,1,1 1,0,0,0,0,0,0,0,0,0 1,0,0,0,0,0,0,0,0,0 1,1,1,1,1,1,1,1,1,1 1,1,1,1,1,1,1,1,1,1 1,1,1,1,1,1,1,1,1,1 -20000,0,0,0,0,0,0,0, 0,-12768 20000,0,0,0,0,0,0,0, 0, 12767 -20000,0,0,0,0,0,0,0, 0,-12769 20000,0,0,0,0,0,0,0, 0, 12768 0,0,0,0,0,1,0,0,0,0 1,1,1,1,1,1,1,1,1,1 |
1 1 10 11 10 1 1 10 10 -1 1 1 1 1 6 0 |
10 11 1 1 2 1 0 0 -1 1 10 10 10 10 1 - |
10 - 1 - Выход за границы массива 1 0 0 - - -32768 32767 -32769 32768 1 Выход из програм- мы SUM |
1 1 1,3 1 1 1,3 1,3 1,3 1 1 2 2 2 2 3 1 |
Отладку программы осуществим по следующему протоколу.
1. Загрузить программу из файла SUM.DPR в окно редактора и запустить ее на выполнение.
2. Ввести входные данные, соответствующие тесту 1 (см. табл.4). Обратить внимание, что значения элементов массива, выводимые процедурой putarr для контроля, отличаются от значений, введенных процедурой getarr.
3. Проанализировать ситуацию. Обнаруженное различие значений обусловлено ошибкой в процедуре ввода getarr или в процедуре вывода putarr.
4. Проверить процедуру ввода. Для этого:
а) поместить в окно отладки Watch List имя массива Arr, указав имя массива в тексте программы и нажав клавиши Ctrl-F5;
б) добавить в окно отладки имя массива М (формального параметра в процедуре getarr), нажав клавишу INS (Insert) и набрав имя массива с последующим нажатием Enter;
в) находясь в окне отладки (Ctrl-Alt-W), выполнить трассировку процедуры getarr, нажимая клавишу F7 и вводя значения элементов массива, соответствующие тесту 1;
г) перед выходом из процедуры getarr и после выхода из нее убедиться, что массив Arr не содержит значений, введенных в массив М.
5. Проанализировать ситуацию. Значения, вводимые в процедуре getarr, не передаются в вызывающую программу. Поскольку при трассировке процедуры в окне отладки наблюдалось правильное заполнение массива М, то ошибку следует искать не в операторах, обеспечивающих ввод элементов массива, а в заголовке процедуры: формальный параметр М должен быть описан как параметр-переменная.
6. Исправить ошибку. Перейти в окно редактора, содержащее текст программы SUM. Вставить зарезервированное слово VAR перед именем параметра М в заголовке процедуры getarr.
Отменить режим трассировки, нажав клавиши Ctrl-F2.
7. Проверить исправленную процедуру ввода. Для этого перейти в окно отладки Watch List и выполнить трассировку процедуры getarr, как указано в пункте 4в. Убедиться, что после выхода из процедуры getarr массив Arr содержит введенные значения элементов.
8. Продолжить выполнение программы, нажав клавиши F9.
Убедиться, что для теста 1 программа вместо вычисления суммы выводит сообщение "Выход за границы массива".
9. Проанализировать ситуацию. Появившееся на экране сообщение выводится из-за того, что не удовлетворяется условие f+n<SIZE в условном операторе, записанном в строке 53 (см. рис.1). Поскольку входные данные являются допустимыми, то ошибка содержится в проверяемом условии f+n<SIZE. Из анализа граничных значений переменных f и n следует, что правильным будет условие f+n-1<=SIZE.
10. Исправить ошибку. Поместить курсор в строку 53 программы и набрать правильное условие f+n-1<=SIZE.
11. Повторить выполнение программы для теста 1. Убедиться, что вместо ожидаемого результата возникает семантическая ошибка, сопровождаемая сообщением "Range check error".
12. Проанализировать ситуацию. Место ошибки указано курсором: это оператор присваивания в функции getsum (строка 41).
Нужно разобраться, в какой момент выполнения функции возникает ошибка в операторе присваивания.
13. Проверить функцию getsum. Установить курсор в строку 54. Выполнить программу для теста 1 до этой строки, нажав клавишу F4. Перейти в окно отладки Watch List и добавить в него имена глобальных переменных f, n, и локальных переменных n1, k, i, sum1, используемых в функции (см. пункт 4б). Выполнить трассировку функции getsum, нажимая клавишу F7 и наблюдая за значениями переменных в окне отладки до тех пор, пока не появится сообщение об ошибке.
14. Проанализировать ситуацию. В разделе операторов функции
перед выполнением цикла, в котором суммируются элементы, значение переменной sum1, отображаемое в окне отладки, имеет ненулевое значение. Это является ошибкой, которая исправляется записью оператора
sum1 := 0;
перед циклом.
Наблюдение за значениями переменных во время трассировки цикла показывает, что сложение элементов массива выполняется правильно до тех пор, пока не доходит очередь до последнего элемента (i=10): при попытке выполнить оператор присваивания
sum1 := sum1 + M[n1+i]
возникает семантическая ошибка, сопровождаемая сообщением "Range
check error". Эта ошибка связана с тем, что неправильно задан индекс элемента (при n1=1 и i=10 индекс n1+i равен 11). Правильным является индекс n1+i-1.
15. Исправить ошибки. В окне редактора набрать оператор sum1 := 0;
перед циклом в функции getsum и исправить индекс на n1+i-1.
16. Проверить исправленную функцию. Для этого установить
курсор в строку 42, в которой заканчивается описание функции
getsum, и выполнить программу для теста 1 до этой строки, нажав
клавишу F4. Перейти в окно отладки и убедиться, что сумма вычислена правильно.
17. Продолжить выполнение программы, нажав клавиши F9.
Убедиться, что программа выводит неправильный результат.
18. Проанализировать ситуацию. Поскольку проверено, что
внутри функции сумма вычисляется правильно, то ошибка может быть обусловлена тем, что вычисленный результат не передается из функции в вызывающую программу. Действительно, анализ описания функции показывает, что пропущен оператор
getsum := sum1
необходимый для передачи вычисленной суммы элементов массива.
19. Исправить ошибку. Перейти в окно редактора и в конце
описания функции getsum перед словом end набрать оператор
getsum := sum1
20. Проверить исправленную функцию. Для этого выполнить программу для теста 1, нажав клавиши F9. Убедиться, что получен ожидаемый результат.
21. Продолжить тестирование программы. Ввести входные дан-
ные, соответствующие тестам 2-12 (см. табл.4), и убедиться, что
результаты выполнения программы совпадают с ожидаемыми. Выполнить
программу для теста 13, который предназначен для проверки работы
программы с входными данными, сумма которых оказывается меньше
минимально возможного числа типа smallint. Убедиться, что для
теста 13 программа выводит неправильный результат.
22. Проанализировать ситуацию. Неправильный результат для
теста 13 обусловлен особенностью выполнения арифметических операций над величинами целого типа (в данном случае над величинами типа smallint): тип результата совпадает с типом операндов, причем возможное переполнение результата никак не контролируется; если операнды относятся к различным целым типам, то тип результата совпадает с типом того операнда, который имеет максимальный диапазон значений.
Можно проверить, как суммируются элементы массива для теста 13 в функции getsum. Для этого установим условную точку прерывания в строке 41 (см. рис.1) и посмотрим, что происходит при сложении 10-го элемента массива:
а) поместить курсор в строку 41 и установить в этой строке точку прерывания, нажав клавиши F5; в результате строка 41 выделяется красным цветом;
б) вывести список точек прерывания, выбрав команду View Debug Windows| Breakpoints;
в) вызвать окно редактирования точки прерывания, нажав клавиши Ctrl-E;
г) в третьей строке окна набрать условие прерывания i=10, при котором выполнение программы приостановится, и нажать Enter, а затем Esc.
д) выполнить программу для теста 13, нажав клавиши F9; после сложения девяти элементов массива в getsum, когда удовлетворится условие прерывания i=10, выполнение программы приостановиться в строке 41 перед оператором присваивания;
е) перейти в окно отладки Watch List и убедиться в правильности значения переменной sum1, равном -20000;
ж) нажать клавишу F7, чтобы прибавить 10-й элемент массива, равный -12769, и убедиться, что переменная sum1 принимает неправильное значение;
з) отменить режим отладки, нажав клавиши Ctrl-F2, и удалить точку прерывания, поместив курсор в строку 41 и нажав F5.
Итак, если не изменять тип результата, вычисляемого функцией getsum, то для некоторых сочетаний элементов массива Arr сумма будет вычисляться неправильно. Поэтому следует заменить тип результата smallint типом longint, чтобы правильность суммы не зависила от допустимых значений элементов массива (-32768..+32767).
23. Исправить ошибку. В строках 35 и 38 заменить тип результата функции и переменной sum1 типом longint.
24. Проверить исправленную функцию. Для этого, нажав клавиши Ctrl-F9, выполнить программу для двух тестов, в которых суммируются (1) 10 элементов, равных -32768, и (2) 10 элементов, равных
32767. Убедиться в правильности полученных результатов.
25. Продолжить тестирование программы. Ввести входные данные, соответствующие тестам 13-16 (см. табл.4), и убедиться, что результаты выполнения программы совпадают с ожидаемыми.
После завершения тестирования отладку программы можно закончить и с большой вероятностью считать, что других ошибок в программе нет.