Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Програмирование. Структурное програмирование, подпрограммы, строки. Учебное пособие
.pdf
щий модуль. В других случаях «заглушка» может выдавать значения,
заданные заранее или вычисленные по упрощенному алгоритму.
Таким образом, сначала создается логический скелет программы,
который затем обрастает плотью кода.
Можно применять к процессу программирования восходящую технологию – написать и отладить сначала модули нижнего уровня, а затем объединять их в более
крупные фрагменты, но этот подход имеет
ряд недостатков.
Во-первых, в процессе кодирования верхнего уровня могут быть
вскрыты те или иные трудности проектирования более низких уровней
программы (просто потому, что при написании программы ее логика
продумывается более тщательно, чем при проектировании). Если подобная ошибка обнаруживается в последнюю очередь, требуются до
полнительные затраты на переделку уже готовых модулей нижнего
уровня.
Во-вторых, для отладки каждого модуля, а затем более крупных
фрагментов программы требуется каждый раз составлять свои тестовые примеры, и программист часто вынужден имитировать то окружение, в котором должен работать модуль. Нисходящая же технология
программирования обеспечивает естественный порядок создания
те-
стов – возможность нисходящей отладки, которая рассмотрена далее.
Этапы проектирования и программирования совмещены во времени: в идеале сначала проектируется и кодируется верхний уровень, затем – следующий и так далее. Такая стратегия применяется потому,
что в процессе кодирования может возникнуть необходимость внести
изменения, отражающиеся на модулях нижнего уровня.
Нисходящее тестирование. Этот
этап записан последним, но это
не значит, что тестирование не должно проводиться на предыдущих
этапах. Проектирование и программирование непременно должны сопровождаться написанием набора тестов – проверочных исходных
данных и соответствующих им наборов ожидаемых результатов.
Необходимо различать процессы тестирования и отладки программы.
Тестирование – это процесс выполнения программ с целью обнаружения
логических ошибок.
Логической ошибкой считается любое несоответствие работы программы заданной на нее спецификации.
Хорошим считается тест, который имеет высокую вероятность обнаружения еще не выявленной ошибки. Удачным считается тест, который обнаруживает еще не выявленную ошибку.
71
-

Отладка программы – это процесс, осуществляемый после удачного выполнения теста. Процесс отладки начинается при обнаружении
ошибки (например, при удачном завершении теста) и проводится в два
этапа:
определяются природа и местонахождение подозреваемой
ошибки в программе;
фиксируется или исправляется ошибка.
Отладка – процесс исправления ошибок в программе, при этом
цель исправить
все ошибки не ставится. Исправляют ошибки, обнаруженные при тестировании. При планировании следует учитывать, что
процесс обнаружения ошибок подчиняется закону насыщения, т. е.
большинство ошибок обнаруживается на ранних стадиях тестирования, и чем меньше в программе осталось ошибок, тем дольше искать
каждую из них.
Для исчерпывающего тестирования программы необходимо прове-
рить
каждую из ветвей алгоритма. Общее число ветвей определяется
комбинацией всех альтернатив на каждом этапе. Это конечное число,
но оно может быть очень большим, поэтому программа разбивается на
фрагменты, после исчерпывающего тестирования которых они рассматриваются как элементарные узлы более длинных ветвей. Кроме
данных, обеспечивающих выполнение операторов в требуемой последовательности,
тесты должны содержать проверку граничных условий
(например, переход по условию х > 10 должен проверяться для значений, больших, меньших и равных 10). Отдельно проверяется реакция
программы на ошибочные исходные данные.
Идея нисходящего тестирования предполагает, что к тестированию
программы приступают еще до того, как завершено ее проектирование.
Это позволяет раньше опробовать основные межмодульные
интерфейсы, а также убедиться в том, что программа в основном удовлетворяет
требованиям пользователя. Только после того как логическое ядро испытано настолько, что появляется уверенность в правильности реализации основных интерфейсов, приступают к кодированию и тестированию следующего уровня программы.
72

КОНТРОЛЬНЫЕ ВОПРОСЫ
1. Что такое структурное программирование?
2. В чем достоинство структурного программирования?
3. В чем смысл принципа «разделяй и властвуй» применительно к
разработке программ?
4. В чем смысл принципа «иерархического упорядочения» приме-
нительно к разработке программ?
5. В чем смысл принципа «слабой связанности» (Low Coupling)
применительно к разработке программ?
6. В
чем смысл принципа «сильного сцепления» (High Cohesion)
применительно к разработке программ?
7. Какие конструкции относятся к базовым конструкциям струк-
турного программирования?
8. Какие задачи решаются на этапе «анализ требования»?
9. Какие задачи решаются на этапе «проектирование»?
10. Какие задачи решаются на этапе «структурное кодирование»?
11. Какие задачи решаются на этапе «нисходящее тестирование»?
12.
Что такое тестирование программ?
13. Что такое отладка программ?
14. Для чего используют IPO-диаграммы?
73

Приложение
ПРАКТИЧЕСКИЕ ЗАДАНИЯ ДЛЯ ЗАКРЕПЛЕНИЯ
Тема. ПОДПРОГРАММЫ
Задачи
1. Написать и протестировать функцию. Функция получает символ,
изображающий шестнадцатеричную цифру, возвращает соответствующее ей целое число.
2. Написать и протестировать функцию. Функция получает целое
число, соответствующее шестнадцатеричной цифре, возвращает соответствующий ей символ.
3. Написать и протестировать функцию. Функция получает целое
неотрицательное число и основание системы счисления
его р-ичное представление (p принадлежит интервалу от 2 до 16).
4. Написать и протестировать процедуру. Процедура упорядочива-
ет значения трех вещественных переменных x, y, z следующим образом: x <= y <= z.
5. Написать и протестировать функцию. Функция получает три ве-
щественных значения и возвращает наибольшее из них.
6. Написать и протестировать функцию. Функция получает два не-
отрицательных
тель (НОД).
7. Написать и протестировать функцию. Функция получает неот-
рицательное вещественное число с нулевой целой частью и возвращает
его представление в системе счисления с основанием р (p принадлежит
интервалу от 2 до 16).
8. Написать и протестировать функцию. Функция получает строку,
содержащую представление р-ичного
ствующее ему число.
целых числа и возвращает их наибольший общий дели-
целого, возвращает соответ-
74
p, возвращает

9. Написать и протестировать функцию. Функция получает строку,
содержащую представление дробной части р-ичного числа (p принадлежит интервалу от 2 до 16), возвращает соответствующее ей вещественное значение.
10. Написать и протестировать функцию. Функция получает неот-
рицательное десятичное целое значение и номер его разряда, возвращает значение разряда целого числа по номеру.
Нумерация разрядов
справа налево, начиная с 1.
Примеры решений
Задача 3
Условие
Функция получает целое неотрицательное число и основание системы счисления p, возвращает его р-ичное представление (p принадлежит интервалу от 2 до 16).
Решение
В соответствии с заданием функция получает в качестве исходных
значений два значения целого типа и возвращает строковое значение.
Поэтому
в заголовке функции опишем два формальных параметразначения целого типа (integer), а в качестве типа результата, возвращаемого функцией, выберем строковый тип (string). Организуем вычисление p-ичного представления неотрицательного целого числа n с помощью управляющей структуры WHILEDO. Для нахождения значений
разрядов p-ичного представления неотрицательного десятичного целого числа n необходимо это число делить на основание
системы счисления (p) и брать в качестве значения текущего двоичного разряда остаток от деления, частное от деления заносится в n и берется в качестве
делимого для следующего шага. Очевидно, что для значений n от n = 0
и до n = p – 1 цикл не надо выполнять ни разу, потому что 0, 1, …,
p – 1 – p-ичные цифры. Поэтому условием выполнения цикла будет
утверждение: n > p – 1. В теле цикла (в do-части) каждый раз будем
формировать значение текущего двоичного разряда b = n mod p, делимого n = n div p для следующего шага, и добавлять значение текущего
p-ичного разряда b, преобразованное в символьный формат с помощью
функции NumTodig, к строке результата слева. Значение старшего разряда будет последним частным от деления, которое будет содержаться
в n после
выхода из цикла. При описании этой последовательности
75

действий с помощью управляющей структуры WHILEDO получим алгоритм, блок-схема которого представлена на рисунке ниже.
1
n – десятичное целое
число
b – значение текущего
разряда p-ичного
представления n
р – основание системы
счисления
s – строка, содержащая
р-ичное представление
числа n
s:= ‘’
3
b:= n mod p
n:= n div p
s:=
2
NumTodig(b)+s
n > p-1
И
4
s:=
NumTodig(n)
+ s
Пример программы, работающей в режиме консольного приложения Delphi, реализующей приведенную блок-схему с помощью двух
функций NumToDig и NumToPStr, приведен ниже.
program PIntToP;
{$APPTYPE CONSOLE}
uses
SysUtils;
//-----------------описание функции--------------------function NumToDig(d: integer): Char;
//функция получает целое число, возвращает соответствующую ему цифру
begin
case d of
76

0..9: Result:= Chr(d + Ord('0'));
10..15: Result:= Chr(d + Ord('A') - 10);
else Result:= Chr(0);
end;
end;
//-----------------описание функции--------------------function NumToPStr(n,p: integer): String;
//функция получает целое число, возвращает соответствующее p-ичное представление
var
b: cardinal;//значение текущего двоичного разряда
begin
while n > p - 1 do
begin
b:= n mod p;
n:= n div p;
result:= NumToDig(b) + result; //вызов функции
end;
result:= NumToDig(n) + result; //вызов функции
end;
//-------------------------------------------------var
n: integer;//десятичное целое без знака
p: integer = 16;//основание системы счисления
s: String;
begin
write('n = '); readln(n);
//-------------------вызов функции------------ writeln('PStr = ',NumToPStr(n,p));
//-------------------вызов функции------------ s:= NumToPStr(n,p);
writeln('PStr = ',s);
readln;
end.
Тестирование функции
Будем тестировать функцию методом тестирования путей. Среди
возможных путей выполнения функции можно выделить два пути, которые представлены на Е-схеме выполнения функции, полученной из
блок-схемы.
77

3
второй путь
1
2
первый путь
4
По первому пути цикл не выполняется ни разу. Второй путь включает в себя множество путей, на которых цикл выполняется один и более раз.
Необходимо подобрать исходные данные для выполнения программы по каждому из возможных путей.
Набор тестов для тестирования разработанной функции представлен в таблице.
Номер
теста
1 n = 0, p = 2 0 Цикл не выполняется
2 n = 1, p = 2 1 Цикл не выполняется
3 n = 8, p = 2 1000 Цикл выполняется три раза
4 n = 0, p = 16 0 Цикл не выполняется
5 n = 10, p = 16 A Цикл не выполняется
6 n = 15, p = 16 F Цикл не выполняется
7 n = 256, p = 16 100 Цикл выполняется два раза
Исходные данные
Ожидаемый
результат
Путь прохождения
Задача 4
Условие
Написать и тестировать процедуру. Процедура упорядочивает значения трех вещественных переменных x, y, z следующим образом:
x <= y <= z.
Решение
Так как процедура должна в результате своей работы изменять значения переданных ей фактических параметров, ее формальные параметры необходимо описать как параметры-переменные. Для упорядочения значений переменных x, y, z в порядке (x <= y <= z) можно
78

Л
x > y
В этой точке тождественно истинно
утверждение x = min(x, y)
И
Exchange(x, y)
Л
Л
x > z
В этой точке тождественно истинно
утверждение x = min(x, y, z)
y > z
В этой точке тождественно истинно
утверждение x <= y <= z
И
Exchange(x, z)
И
Exchange(y, z)
Блок-схема алгоритма
поступить так: найти минимальное из трех значений и занести его в x;
затем из оставшихся двух значений найти максимальное и занести
его в z. Сначала найдем минимальное значение из трех, с этой целью,
например, можно сравнить x и y. Если x – большее из них, то перемен-
79

ные обмениваются значениями, в противном случае никаких действий
выполнять не надо. После этого x будет содержать наименьшее из двух
значений x, y. Затем необходимо сравнить x и z. Если x – большее из
них, то переменные обмениваются значениями, в противном случае
никаких действий выполнять не надо. После этого x будет содержать
наименьшее из трех значений x, y, z. Теперь необходимо занести
в z
максимальное значение из оставшихся двух. Для этого сравним значения y и z. Если y – большее из них, то переменные обмениваются значениями, в противном случае никаких действий выполнять не надо.
Теперь мы имеем следующее упорядочение значений переменных:
x <= y <= z. Для описания этой последовательности действий будем
использовать последовательность из трех управляющих структур
IFTHEN. Поскольку в
THEN-частях всех управляющих структур
IFTHEN обмениваются значениями две переменные, организуем для
этой цели процедуру Exchange. Так как она должна в результате своей
работы изменять значения переданных ей фактических параметров, ее
формальные параметры необходимо описать как параметры-переменные.
Пример программы, работающей в режиме консольного приложе-
ния Delphi, реализующей приведенную блок-схему с помощью
двух
процедур Exchange и Reorder3, показан ниже.
program PReorder3;
{$APPTYPE CONSOLE}
uses
SysUtils;
//----------описание процедуры-------------procedure Exchange( var a,b: real);
var t: real;
begin
t:= a;
a:= b;
b:= t;
end;
//-----------описание процедуры--------procedure Reorder3( var x,y,z: real);
begin
80
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
