Структурное и модульное программирование

Следующий самый продолжительный этап развития методов программирования — появление и широкое использование языков высокого уровня. Основная особенность этого этапа —большое количество и разнообразие языков программирования. Такие средства программирования можно разделить на универсальные (Алгол, PL/1, Pascal, С и др.) и специализированные языки. Предшественниками языка С были BCPL и язык B. Язык С был разработан в 1970 году Денисом Ритчи, который первым и реализовал его в операционной системе Unix. Наибольшее распространение среди специализированных языков в 60-е — 80-е годы прошлого века получили Fortran для научно-технических расчётов, Cobol для решения экономических задач, Basic для обучения программированию и другие языки.

При использовании таких языков при вычислении того же выражения достаточно его записать по простым естественным правилам (например, r=a+b*c). Всю дальнейшую работу система берёт на себя. Аналогично при программировании ввода-вывода количество записываемых программистом команд (операторов) намного меньше, чем в языках низкого уровня типа Ассемблер.

При использовании больших вычислительных машин практиковалось в основном “заочное” написание, отладка и тестирование программ. При этом программист имел ограниченный доступ к ЭВМ. Программы писали на специальных бланках, затем их отдавали на перфорацию. Полученный пакет перфокарт компилировали и в случае успешной компиляции вместе с исходными данными отдавали на выполнение. Программист анализировал полученный бумажный вариант результатов компиляции и выполнения, вносил в колоду перфокарт необходимые изменения и повторял отладку. Поэтому разработка даже небольших по объёму программ оставалась трудоёмкой и требовала, как и на начальном этапе развития программирования, больших затрат времени.

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

1) Алгоритм и программа должны разрабатываться поэтапно, по шагам. На начальном этапе проектирования сложная задача (проект) должна разбиваться на более простые части (блоки), каждая из которых должна разрабатываться независимо друг от друга. На следующем этапе детализации все или некоторые из этих частей в свою очередь разбиваются на отдельные подзадачи и так далее. Степень детализации и количество таких уровней зависят от характера, объёма, логической сложности задачи, от используемого языка программирования. На языке блок-схем этот принцип означает, что сначала составляется укрупнённая блок-схема, отражающая логику всей задачи, весь алгоритм в целом. На втором уровне записываем более подробные блок-схемы некоторых или всех блоков. При необходимости могут быть составлены схемы следующих уровней с большей степенью детализации. Этот принцип в литературе называется по-разному: метод (принцип) последовательного построения (уточнения) алгоритма; принцип поэтапной детализации алгоритма; метод нисходящего (сверху вниз) проектирования.

2) Логика любой программы должна опираться на минимальное количество следующих достаточно простых базовых (основных, типовых) управляющих (алгоритмических, логических) структур (конструкций) (БАС): ветвление (или развилка); повторение (или цикл); следование. В скобках приведены различные встречающиеся в литературе названия этих понятий. Первая из структур программируется с помощью полной и сокращённой формы оператора if и вспомогательного оператора выбор (switch на языке Си, case в Pascal и др.). Основными операторами цикла являются оператор цикла с предусловием (while) и с постусловием (do … while на языке Си, repeat … until в Pascal и др.). Несмотря на широкое использование оператора for и его различных модификаций (например, в Visual Basic), этот оператор следует отнести к вспомогательным операторам, так как его всегда можно заменить оператором while. Для программной реализации структуры “следование” не существует оператора. Во всех языках программирования команды выполняются последовательно в том порядке, как они записаны, если не используются операторы, меняющие этот естественный порядок.

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

При этом структурированный алгоритм (программа) должны представлять собой композицию из последовательных или вложенных друг в друга перечисленных выше базовых алгоритмических структур. Например, сначала может быть записан цикл for, а затем вне этого цикла — оператор if. Вложенность БАС имеет место, например, если внутри цикла while встречается оператор выбора switch или наоборот, в одной или в нескольких ветвях if может быть оператор цикла..

3) Важным и самым сложным является следующий принцип. Каждая из БАС должна иметь один вход и один выход. Поэтому структурное программирование в литературе часто называют программированием без оператора goto, который нарушает это требование. Большинство авторов считают плохим стилем программирования, если часто без необходимости используется данный оператор. В то же время запретить его использование было бы неправильно. Иногда этот оператор помогает проще запрограммировать сложные алгоритмы. Например, может возникнуть необходимость в операторе goto, если надо выйти из самого внутреннего цикла за пределы всех циклов при условии, что уровень вложенности их достаточно большой (например, 4 вложенных цикла).

Кроме оператора goto, это требование нарушается при использовании таких операторов, как break, return и некоторых других. Более того, в некоторых современных системах программирования (например, java) возможности break расширены. Это говорит о том, что этот принцип в настоящее время не всегда соблюдается.

Для лучшего его понимания приведём два варианта решения следующей задачи: определить, есть ли в одномерном массиве нуль.

Первый вариант.

const n=5; int a[n]={11,0,-2,3,4}; bool b=false;

for (int i=0;i<n; i++) if (!a[i]) { b=true; break; }

if (b) cout<<" There is 0"; else cout<<" There is not 0”;

Этот вариант не соответствует рассматриваемому здесь принципу, так как из цикла предусмотрены два выхода. Первый с помощью break выполняется, если найден нуль. В противном случае, если нуля нет, выход из цикла осуществляется, потому что условие i<n заголовка оператора for станет ложным.

Второй вариант решения этой же задачи соответствует рассматриваемому принципу структурного программирования.

const n=5; int a[n]={10,11,-2,3,4}; bool b=false;

for (int i=0;(i<n) &&!b; i++) if (!a[i]) b=true;

if (b) cout<<" There is 0"; else cout<<" There is not 0”;

Здесь имеет место один выход из цикла, записанный с помощью сложного логического выражения во второй части заголовка оператора for. Если найдём нуль, выражение (i<n) &&!b станет ложным, несмотря на то, что i<n истинно, так как b=true, а !b=false. Если нуля в массиве нет, то после просмотра всего массива выражение (i<n) &&!b будет ложным, потому что нарушится условие i<n.

Модульное программирование тесно связано со структурным программированием и напоминает его первый принцип. Согласно этой технологии, проект (задача, программа) разбивается на логически завершённые части, которые оформляются по определённым правилам. Эти части чаще всего называют подпрограммами. Каждую из них на следующем этапе можно разбивать на подпрограммы более низкого уровня. Во многих языках использовались два их вида, например, процедуры и функции на языке Pascal, подпрограммы и функции на языке F ortran, которые отличались правилами их оформления и вызова. Есть возможность писать и использовать “свои” локальные подпрограммы (подпрограммы пользователя). Кроме этого, в 70-е — 80-е годы были разработаны и получили широкое применение пакеты прикладных стандартных программ для решения различных задач: математических, задач статистики, анализа и обработки данных, ввода, вывода и др. В некоторых языках, например, языке Pascal, пошли дальше. По определённым правилам можно разрабатывать не просто отдельные подпрограммы, а так называемые модули, содержащие типы, константы, переменные и процедуры и функции для решения определённого комплекса взаимосвязанных задач.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: