- •Введение
- •Глава 1. Организация и технология разработки прикладных программ Математическое обеспечение и его структура
- •Организация разработки прикладных программ
- •Технология разработки прикладных программ
- •Характеристики качества программного обеспечения
- •Структура курса и литература
- •Глава 2. Типы структурированных данных. Статические и динамические типы данных. Файловая структура
- •Типы данных
- •Представление структур в памяти эвм
- •Некоторые примеры представления данных
- •Техника доступа к информации записанной в файле
- •Глава 3. Основные этапы полного построения алгоритма
- •Глава 4. Некоторые основные приемы и алгоритмы
- •4.1 Структурное программирование сверху-вниз и правильность программ
- •4.2 Основные правила структурного программирования
- •4.3. Структурное программирование сверху-вниз: дополнительные соображения
- •4.4.Практические советы при использовании метода структурного программирования
- •1.4. Общая организация программы и ее запись
- •1.4. "Малый программистский стандарт"
- •5. Методы разработки алгоритма
- •5.1. Методы частных целей, подъема и отрабатывания назад
- •5.2 Метод эвристики
- •5.3 Программирование с отходом назад
- •5.4. Метод ветвей и границ
- •5.5. Рекурсия
- •5.6. Моделирование
- •Глава 6. Алгоритмы машинной математики больших массивов данных.
- •6.1. Сортировка
- •6.2. Сортировка массивов
- •6.3. Сортировка последовательностей.
- •6.4. Поиск
- •7. Документирование, сопровождение и эксплуатация программ.
- •7.1.Стандартизация, дисциплина и творчество в программировании.
- •7.2. Виды программ и программных документов
- •7.3. Основные стадии и этапы разработки программ и программной документации
1.4. Общая организация программы и ее запись
Итак, мы рассмотрели сущность структурного программирования, теперь рассмотрим как лучше записать программу, составленную с помощью структурного программирования. Прежде всего отметим, что для ЭВМ форма записи программы безразлична, поэтому можно применить любую форму записи. Следовательно, можно составить программу так, чтобы она была воспринята человеком с наибольшим пониманием. Или другими словами как записать программу так, чтоб облегчить понимание структуры программ.
Основными разновидностями форм записи являются отступы, и изменения числа строк (т.е. применения метода когда несколько операторов записаны в одной строке, или разных строках). В настоящее время уже сложились определенные правила по которым записываются программы. Эти правила получили название так называемого «малого программистского стандарта». Рассмотрим их.
1. Цикл.
Короткие циклы, которые помещаются в одну строку, лучше так в одной строке и записывать: '-
FOR I..... : ......... : NEXT I;
Длинные циклы записываются со смещением тела цикла:
FOR I.....:
Оператор
Оператор
NEXT I
Если у кратных циклов общее начало и/или конец, то их можно записать так:
FOR I.....: FOR J
Оператор
Оператор
NEXT J : NEXT I
Если цикл организован операторами, моделирующими условие «пока», или с помощью операторов IF, то целесообразно его также записывать со смещением вправо тела цикла, аналогично записи оператора FOR
2. Ветвление
Короткие операторы IF записываются в одну строку:
IF . . . THEN . .. ELSE ...
Более длинные ветвления следует записывать так:
IF . . . THEN . ... _
ELSE....
где подчеркивание знак продолжающейся строки.
Длинные операторы IF записываются в операторной форме:
IF ... THEN
Оператор
Оператор
.....
Оператор
ELSE
Оператор
Оператор
.....
Оператор
END IF
3. Обход. Это частный случай ветвления и записывается так же, только без ELSE (или соответствующих ELSE) операторов.
4. Длинные операторы.
Если оператор не помещается в строку, то его продолжение следует записывать со смещением, причем не безразлично, в каком месте сделан перенос. Например:
INPUT А (1), N (1) , SKIP, F (8,3) ,F (3), N_
(2,3),FF
читается хуже, чем
INPUT А (1), N (1) , SKIP, F (8,3) ,F (3), _
N(2,3),FF
5. Объединение в строку.
Если язык позволяет размещать несколько операторов в одной строке, то в строку следует группировать логически связанные операторы, выполняющие законченные действия или родственные функционально.
Очевидно, что запись
I=1
X=RO*COS(FI);
Y = RO * SIN (Fl) ;
читается хуже, чем
I=1
X=RO*COS(FI): Y = RO * SIN (Fl) ;
так как объединение последних двух операторов в строку подчеркивает их функциональное единство (перевод из полярных координат в обычные) и выделяет первый оператор (установка начального значения какого-то индекса или счетчика). В строку должны быть сгруппированы операторы так, чтобы каждую строку можно было кратко откомментировать.
Например:
DISKR=SQRT(B**2-4*A*C): А2=2*А ‘ВСПОМОГ. ДЕЙСТВИЯ
XI=(-B+DISKR)/A2: X2=(-B-DISKR)/A2 ‘КОРНИ
6. Группировка внутри строки. Увеличив интервалы между некоторыми операторами, можно дополнительно улучшить восприятие программы. Например, если строку начальных значений программы записать
МАХТ=С: MINT=D: IMAXT=0: IMINT=0
или
МАХТ=С: IМАХТ=0: MINT=D: IMINT=0
сгруппировав отдельно сведения о максимуме и сведения о минимуме или же разделив значения и индексы, то это читается легче, чем сплошной текст:
ÌÀÕÒ=Ñ: IMAXT=0: MINT=D: IMINT=0
По тому же принципу следует группировать операторы и на схемах: в один линейный блок объединяются функционально родственные вычисления, тогда при программировании переход к новому блоку схемы сопровождается переходом к новой строке программы.
Некоторые авторы (например, [14]) рекомендуют записывать в каждой строке только один оператор. Эта рекомендация безусловно неправильна: историческое развитие языков щло от Фортрана, где допускается только один оператор в строке, к Алголу-60, ПЛ/1 и т.д., где допускается несколько операторов в строке, — непонятно, почему этой возможностью не следует пользоваться.
Смещение на каждом шаге лесенки не должно быть большим, обычно оно на уровне следующего лексического слова: четырех — шести позиций вполне достаточно. Такая лесенка хорошо смотрится и на листинге, и на экране дисплея.
Желательно писать программы без меток, но если они встречаются в программе, то должны быть вынесены в начало строки и должны выступать из общего текста программы влево, чтобы их было легко найти. К началу строк выносятся заголовки блоков, начала крупных циклов и крупных составных операторов. Операторы NEXT, END должны размещаться либо в той же строке, что и соответствующий им оператор, например FOR, IF или BEGIN, либо под парным ему FOR, IF или BEGIN.
Для удобства чтения программа должна быть хорошо откомментирована. Можно предложить следующие правила комментирования.
1. Каждая программа или подпрограмма должна начинаться с комментария, в котором на русском языке записано, что делает эта программа.
2. Идентификаторы должны быть мнемоничны (хорошая мнемоника очень существенно дополняет комментарии). За заголовком программы или подпрограммы должны быть откомментированы все основные идентификаторы и расшифрована их мнемоника. Например: NSTR — номер обрабатываемой строки.
3. В тексте программы должны размещаться комментарии, представляющие собой краткий заголовок, характеризующий действия, выполняемые до следующего комментария. Комментирование каждого оператора бессмысленно, так как оно может только повторить то, что делает этот оператор и что можно понять, прочтя оператор. Если операторы позволяют понять, как работает программа, то комментарий должен пояснить, что и зачем делают эти операторы. Например, для программы решения системы линейных уравнений методом Гаусса примерно на 60 операторов текста достаточно четырех комментариев: "Цикл по шагам", "Пересчет строки", "Перестановка строк", "Обратный ход: вычисление Х (1)", связывающих фрагменты текста программы с основными этапами алгоритма.
4. Все выдаваемые программой печати должны быть с поясняющими словами: вместе с содержимым переменных должны печататься либо их идентификаторы, либо поясняющий текст на русском языке — такой текст служит хорошим комментарием как к результатам работы программы, так и к тексту операторов вывода.
Для удобства пользования программой следует хорошо продумывать ввод-вывод. Помимо поясняющих слов на выводе следует обеспечить естественность форматов:
матрица должна печататься по строкам в виде матрицы (а не в одну строку),
на одном файле должно помещаться целое число строк многомерного массива (например, матрицу размером 5Õ5 не следует вводить по 7 чисел со строки) и т.д.
Программа может быть оформлена как единая головная программа или же из нее могут быть выделены подпрограммы, наконец, вся программа может быть оформлена как процедура. Такое оформление алгоритма или его части в виде процедуры обычно преследует одну из следующих целей:
а) придание алгоритму общности,
б) сокращение общего объема программы за счет возможности одной процедурой обрабатывать различные переменные, массивы и т. д„
в) сокращение времени разработки и отладки программы за счет параллельного программирования и отладки процедур,
г) сокращение времени трансляции: отлаженная процедура записывается в библиотеку или выдается файлом в транслированном виде и более не транслируется.
Для получения достаточно универсальных и удобных в использовании процедур необходимо оформлять их с учетом некоторых правил.
1. Обмен данными с процедурами. Для получения процедурой данных из другой программной единицы и для выдачи в другую программную единицу полученных результатов служат параметры (к которым мы отнесем также глобальные переменные и общие области). Прочие работающие в процедуре идентификаторы никакого отношения к совпадающим по названию идентификаторам других программных единиц не имеют. Параметры - это "окна во внешний мир", через которые процедура получает исходные данные и отдает свои результаты.
Параметры можно разделить на две группы: а) входные, через которые процедура получает исходные данные; б) выходные, через которые она отдает результаты своей работы.
Некоторые параметры могут относиться одновременно к обеим группам. Таким образом, в параметры следует включать только те переменные, через которые идет обмен информацией с другими программными единицами. Все прочие переменные, которые используются в процедуре, в параметры включать не следует, так как использование этих переменных — это внутреннее дело процедуры и больше эти переменные никого не интересуют.
2. Процедуры-функции. Процедуры, которые выдают в качестве результата только одно значение (не массив), оформляются как функции. У функции на один формальный параметр меньше, так как в качестве выходного параметра используется идентификатор функции. Функция удобнее в использовании, так как ее результат можно непосредственно использовать в выражении без предварительного присваивания.
3. Ввод-вывод в процедурах. Процедуры содержат операторы ввода-вывода в редчайших случаях. Исключение составляют только процедуры, специально созданные для ввода-вывода, например, процедура печати графика на принтере своим единственным результатом имеет напечатанный график.
4. Проверка применимости алгоритма. Многие алгоритмы могут не давать результата в ряде случаев (например, система линейных уравнений не всегда имеет решение). Процедуры, реализующие такие алгоритмы, имеют свои особенности программирования. Общий принцип заключается в том, что при любых исходных данных процедура должна доработать до конца и выдать либо результат, либо сообщение о невозможности получить результат. Из этого вытекают два следствия.
Следствие 1. Там, где может случиться аварийная ситуация, должны быть предусмотрены соответствующие проверки и действия по устранению или обходу этой ситуации или же выдаче сообщения. Например, при решении системы линейных уравнений по компактной схеме Гаусса необходимо делить элементы строки на диагональный элемент. Если этот элемент близок к нулю, то возникнет аварийная ситуация (переполнение или деление на нуль), в результате которой программа будет снята с решения. Следовательно, перед делением надо проверить этот элемент на близость нулю и при необходимости выполнить перестановку строк, а если подходящей для перестановки строки нет, то выдать сообщение о неразрешимости системы.
Следствие 2. Процедура, реализующая алгоритм, который может не дать результата, должна иметь дополнительный (сигнальный) параметр, по которому определяют успешность работы процедуры. Этот выходной параметр обычно бывает целой или логической переменной или меткой. Целесообразно параметр объявлять логической переменной, если ошибка зависит от одного фактора. Если причин неразрешимости несколько и существенно то, по какой из них невозможно получить результат, то параметр лучше сделать целой переменной, принимающей значения: 0 — если решение получено, 1 — если система несовместна, 2 — если решений бесконечно много и т.п. (иногда можно помимо выдачи признака аварийной ситуации через параметр выполнить печать причины в самой процедуре, но возврат в обратившуюся программу и сигнальный параметр остаются обязательными). Наконец, параметр может быть меткой, по которой происходит выход при неразрешимости системы. Однако следует помнить, что вариант с меткой нарушает структурность обращающейся к процедуре программы.
Чтобы лучше понять, к чему приводит нарушение описанного принципа, представьте, что Вы попросили товарища узнать время отправления самолета, рейс оказался отложенным на неопределенное время и товарищ уехал домой, не сообщив Вам ничего: Вы же просили узнать время, а ему не удалось.