Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Аверянов Современная информатика 2011

.pdf
Скачиваний:
113
Добавлен:
16.08.2013
Размер:
6.43 Mб
Скачать

{

printf("input n\n" ) ; scanf(" %d ", &n ); for( i = 0; i <n; i++)

{

printf("input a(%d)\n", i ); scanf("%g",&a[i ]);

}

numax=numin=0; for( i=1;i<n;i++)

{

if (a[ i ] > a[numax])numax=i ; if (a[ i ] < a[numin] )numin=i;

}

printf( "max{a( i ) }=%g min{a( i)}=%g" ,a[numax] ,a[numin] ) ;

}

В основе создаваемых языков, как правило, лежит некоторая основополагающая идея или, как говорят теоретики программирова-

ния, парадигма.

Рассмотренные средства составляют начальный уровень программирования, основная идея которого характеризуется как хаотическое программирование, типичным представителем этого направления был Бейсик. Программа на Бейсике представляла единый текст с большим количеством переходов к помеченным участкам (с помощью меток), и работа велась в режиме интерпретации (построчного выполнения). Однако появление сложных технических систем приводит к увеличению объема обрабатываемых данных, повышению сложности обработки, значительному увеличению размеров программ и появлению программных комплексов. Увеличение размеров программ довольно быстро выявило ограниченность этого подхода, связанного с невозможностью распараллеливания работы между программистами и сложностью диагностики ошибок.

Первый шаг в решении этой задачи был сделан разработчиками Фортрана, что связано с развитием так называемого процедурноориентированного, или модульного, программирования. Концепция этого направления в развитии программирования была предложена М. Уилксом в 1957 г. и заключалась она в следующем.

Программу можно составлять из отдельных автономных функциональных модулей, транслируемых независимо, которые могут вызываться многократно и использоваться различными програм-

221

мами (рис. 5.4). Модули, собранные по определенной тематике – математические, графические, экономические и т.п., объединяются в библиотеки.

Основная программа

Внешние подпрограммы

Рис. 5.4. Схема работы программы, многократно использующей внешний модуль

На первом этапе такие модули в объектном виде включались в виде внутренних библиотек в транслятор языка и подключались на уровне компоновки в исполнимую программу. К ним относились продпрограммы – функции для вычисления наиболее распространенных математических функций (тригонометрических, логарифмов, MIN, MAX и т.п.). Затем средства разработки этих модулей были включены в стандарт языка, и разными фирмами было разработано большое количество внешних подпрограмм для различных приложений. Так, фирма IBM разработала библиотеку научных подпрограмм на Фортране, в которую были включены практически все разделы вычислительной математики. В России была разработана библиотека графических подпрограмм на Фортране (ГРАФОР). Кроме этого в различных организациях было создано большое количество узкоспециализированных библиотек.

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

222

Такой подход позволяет:

1)сократить текст основной программы путем включения дополнительных (внешних) модулей на уровне компоновки (иногда многократного включения одних и тех же модулей на различных фазах выполнения программы);

2)распараллеливать выполнение проекта, распределяя работу между программистами;

3)структурировать программу, облегчая ее тестирование и поиск ошибок.

Этот подход при проектировании сложных систем называется восходящим проектированием (или проектированием снизу вверх).

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

Фортран включает три структуры, использующие указанные принципы.

Первой структурой является оператор функции, которая, правда, не полностью отвечает вышеприведенным свойствам и не является внешней, а определяется в рамках единого текста программы и транслируется совместно с основной программой. Основное назначение ее заключается в следующем. Если в программе используется длинное арифметическое (или какое-то другое) выражение, которое по ходу программы необходимо многократно вычислять с различными аргументами, то в разделе описаний необходимо дать его формальное определение:

Name(arg) = EXPRESSION

где Name – имя оператора функции; arg – список формальных параметров; EXPRESSION – само выражение.

Например, в программе необходимо многократно вычислять

выражение:

ах2 + by2 + cxy + d

Его можно оформить, как оператор функции: QUAD(X,Y)=A*X**2+B*Y**2+C*X*Y+D

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

223

Например: RESULT=X4+200*QUAD(X1,Y1)+300*QUAD(X2,Y2)+400*QU

AD(X3,Y3)

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

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

Первый модуль – подпрограмма функции, которая определяется следующим образом:

t FUNCTION f(a1,a2…an)

t – тип функции, может быть: Integer, Real, Double Precision,

Сomplex, Logical; по умолчанию Real или Integer определяется первой буквой имени функции; FUNCTION – ключевое слово; f – имя функции; a1,a2, …, an – имена формальных параметров.

Структура этой подпрограммы следующая:

FUNCTION Name(a1, a2, …, an)

исполнительная

часть

Name=Result

Return

End

После выполнения основной (исполнимой) части имени функции присваивается значение полученного результата ее работы (Result). Оператор Return передает результат в вызывающую программу (End – указание транслятору о завершении текста подпрограммы при трансляции).

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

224

ных), указанных в скобках (аналогично вызову оператора функции).

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

В качестве примера рассмотрим подпрограмму функции для скалярного произведения двух векторов X и Y.

Алгоритм скалярного произведения: n

S= ∑ Xi·Yi i=1

FUNCTION SKALAR(X,Y,N)

DIMENSION X(100),Y(100) s=0.0

do 1 i=1,N s=s+X(i)*Y(i)

l Continue SKALAR=s RETURN

END

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

Существует еще один вид модулей более универсального назначения, который в Фортране называется SUBROUTINE, в Паскале – PROCEDURE (в отличие от SUBROUTINE подпрограмма PROCEDURE является внутренним программным модулем, доступ к которому возможен только из самой вызывающей программы, в состав которой он входит). В языке С, хотя все модули называются

225

функциями, которые вызываются из главной программы (main) с

возможностями SUBROUTINE и PROCEDURE.

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

Программа SUBROUTINE оформляется следующим образом:

SUBROUTINE S(a1, a2, …, an)

Тело подпрограммы Исполнительная часть

RETURN

END

где SUBROUTINE – ключевое слово; S – имя подпрограммы (не имеет типа и никак не связано с входными и выходными параметрами); a1, a2, …, an – формальные параметры, используемые при работе подпрограммы, включая и выходные параметры (результаты вычислений). Формальные и фактические параметры должны быть согласованы между собой (так же, как и в подпрограмме функции) по типу, количеству и порядку следования. Естественно выходные (вычисляемые) параметры фигурируют в главной программе только в виде имен (не имеющих значений до начала работы модуля). RETURN и END – выполняют те же функции, что и в подпрограмме функции.

В качестве примера использования SUBROUTINE рассмотрим математический алгоритм перемножения матрицы на вектор:

SUBROUTINE MATRIX(A,X,Y,N) DIMENSION F(50,50),X(50),Y(50) DO 2 I=1,N

s=0.0 DO1 I=1,N

1s=s+A(I,J)*X(j)

2Y(I)=s END

RETURN

END

226

В данном случае значения всех параметров передаются из главной программы, и в результате работы этой SUBROUTINE в главную программу возвращается вычисленное значение вектора Y(I).

Вызов подпрограммы SUBROUTINE осуществляется следующим оператором:

CALL METRIX(a1, a2, …, an)

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

Следующее направление в развитии языков программирования (парадигма программирования) обычно связывают с так называе-

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

Появление парадигмы структурного программирования обычно связывается с разработкой Никлаусом Виртом языка Pasсal в 1972 г. Основное назначение этого языка изначально связано с обучением студентов программированию. Следует отметить, что Вирт – одна из ключевых фигур в создании программистской идеологии. Он разработал также такие языки, как Modula, Oberon, Object Pascal. Справедливости ради необходимо отметить, что большую популярность Pasсal приобрел благодаря очень удачной среде Turbo Pascal, разработанной фирмой Borland. При этом стандарт «оригинального» языка значительно расширен фирмой. Что же касается структурного программирования по отношению к языку

227

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

1.При организации программы Pasсal придерживается более строгого подхода. Обязательной является описательная (неисполняемая) часть, которая оформляется с помощью специальных синтаксических структур с описанием всех используемых системных модулей и встроенных процедур и функций, а также с описанием всех используемых параметров с именами переменных, констант, массивов и т.п. (т.е. принятые в Фортране умолчания не допускаются).

2.Включаются в текст программы структуры FUNCTION и PROCEDURE, функционально являющиеся полным аналогом FUNCTION и SUBROUTINE, но в отличие от Фортрана они являются внутренними подпрограммами, транслируемыми вместе с основной программой, и недоступны извне.

3.Используются блочные конструкции begin…end, придающие автономность отдельным частям текста программы, продолжение выполнения которой возможно только после завершения выполнения участка, заключенного в эти скобочные конструкции.

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

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

Так, если основная критика Фортрана связана с оператором безусловного перехода (go to) и наличием меток, что приводит в больших программах к «паутине» переходов, затрудняя чтение программы и поиск ошибок (нарушает структурированностью), то, тем не менее, в Pascal эти средства также были введены, поскольку они в ряде случаев оказались очень удобны. Локализация имен и

228

меток, наличие глобальных имен также является отходом от основной (генеральной) линии Pascal.

Кроме этого, начиная с определенных версий Turbo Pascal (фирмы Borland), введены автономные (отдельно транслируемые) модули UNIT (по образу и подобию Фортрана). В связи с этим разговоры о структурированности уменьшились, особенно в связи с переходом на парадигму объектно-ориентированного программирования и развитием CASE-технологии. Концепция объектноориентированного программирования представляет современную парадигму традиционного программирования.

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

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

Абстракция процесса – одно из наиболее старых понятий в области разработки языков программирования. Даже язык Plankalkul поддерживал абстракцию процесса. Все подпрограммы являются абстракцией процессов, поскольку они определяют способ, с помощью которого программа устанавливает, что необходимо выполнить некоторый процесс без уточнения деталей того, как именно это можно сделать (т.е. сама реализация этого процесса скрыта от пользователя в вызывающей ЦП программе).

229

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

SORT_int(list,list_len)

Этот вызов является абстракцией реального процесса сортировки (алгоритм которого в вызывающей программе не определен и не зависит от алгоритма в вызываемой программе). Единственным существенным моментом является имя вызываемой подпрограммы (SORT_int), а также указание (передачи в программу SORT_int) массива подлежащего сортировке (list) и имя отсортированного массива, который возвращается в основную программу (list_len).

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

Эволюция абстракции данных сопровождается эволюцией абстракции процесса, поскольку неотъемлемой и главной частью любой абстракции данных являются операции, которые определяются как абстракции процесса. Абстракция данных составляет основу (парадигму) информационно-ориентированного программирования (в противоположность процедурному). Эта парадигма стала популярной в 80-х годах прошлого века. Языки, поддерживающие информационное программирование, часто называются объектными (object_based). Они составляют основу объектно-ориентированного программирования. Появление абстракции данных связано с так называемой инкапсуляцией (скрытая реализация*).

Инкапсуляция – способ объединения в единое целое подпрограмм и данных, которые они обрабатывают. Такое объединение предоставляет пользователю возможность создавать собственные типы данных, аналогичных встроенным типам, используемыми

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

230