04 Программирование на ЭВМ - подпрограммы.pptx
- Количество слайдов: 37
Программирование на ЭВМ Лекция 4. Подпрограммы Доцент, к. т. н. Исаев А. В. avisz@yandex. ru Ауд. 7 или 234
Подпрограммы • Подпрограммы являются мощным средством структурирования программ. • В структурированных программах легче отслеживается алгоритм, такие программы более удобны в отладке и менее чувствительны к ошибкам. Каждой подпрограмме можно поручить какую-то отдельную специфическую задачу, выполнение которой программисту легче контролировать.
Подпрограммы • Подпрограммой называется особым образом оформленный фрагмент программы, имеющий собственное имя. • Упоминание этого имени в тексте программы приводит к выполнению процедуры и называется вызовом подпрограммы. • Сразу после вызова подпрограммы начинают выполняться входящие в нее операторы, а после выполнения последнего из них управление возвращается обратно в основную программу и выполняются операторы, стоящие непосредственно за оператором вызова подпрограммы.
Виды подпрограмм В языке Pascal есть две основные разновидности подпрограмм: • Процедуры • Функции.
Чем отличаются процедуры от функций? • Процедура просто выполняет некоторые действия. Примеры стандартных процедур: writeln(a); readln(b); inc(z); • Функция отличается от процедуры тем, что результат ее работы возвращается в виде значения этой функции и, следовательно, вызов функции (обращение к ней) может использоваться в выражениях (как обычные идентификаторы). Примеры стандартных функций: sin(alpha); sqr(y); low(a);
Общая структура подпрограммы • Нестандартную подпрограмму необходимо предварительно описать, чтобы компилятор мог установить связь между оператором вызова и теми действиями, которые предусмотрены в подпрограмме. • Описание подпрограммы помещается в разделе описаний до начала исполняемых операторов основной программы. • Структура подпрограммы в целом аналогична структуре основной программы: Заголовок подпрограммы; раздел описаний; раздел операторов (тело подпрограммы).
Начало … Операторы основной программы … Вызов подпрограммы … Продолжение основной программы … Конец Подпрограмма (имеет такую же структуру, как и основная программа)
Обмен данными между программой и подпрограммой • Для обмена информацией между основной программой и процедурой могут использоваться один или несколько параметров вызова. • Если они есть, то перечисляются в круглых скобках за именем подпрограммы и вместе с ним образуют оператор вызова подпрограммы. • С параметром: readln(a); • Без параметра: readln;
Параметры вызова • Параметры вызова перечисляются и в операторе вызова подпрограммы, а также описываются в заголовке и теле самой подпрограммы; • Чтобы отличать параметры подпрограммы, описанные в её заголовке и теле, от параметров, указываемых при вызове подпрограммы, используются формальные и фактические параметры. • При вызове подпрограммы фактические параметры, указанные в команде вызова, становятся значениями соответствующих формальных параметров.
Общий вид описания и вызова подпрограмм • Заголовок процедуры: procedure <имя> [(список_формальных_параметров)]; • Заголовок функции: function <имя> [(список_формальных_параметров)]: <тип>; • Здесь <имя> — имя подпрограммы (правильный идентификатор), <тип> — тип возвращаемого функцией результата. • Список формальных параметров необязателен и может отсутствовать. Если же он есть, то в нем должны быть перечислены имена формальных параметров и их типы, например: procedure My. Proc(a: real; b: integer; c: string); Параметры, указываемые при описании подпрограммы, называются формальными, а параметры, указываемые при вызове подпрограммы, – фактическими. При обращении к подпрограмме формальные параметры заменяются на соответствующие фактические параметры вызывающей программы (или вызывающей подпрограммы).
Общий принцип передачи данных в подпрограмму • Еще раз: При вызове подпрограммы её формальные параметры заменяются на фактические в порядке их следования. Этим и обеспечивается передача данных в подпрограмму. • Фактические параметры — это данные, которые передаются подпрограмме при обращении к ней (т. е. записываются при вызове подпрограммы в основной программе) • Формальные параметры — это данные, находящиеся лишь в описании подпрограммы и определяющие тип и место подстановки фактических параметров, над которыми производятся действия. • Описание формальных параметров в заголовке подпрограммы нужно для того, чтобы подпрограмма заранее знала о том, с какими данными, переданными из основной программы, ей предстоит работать. • Между фактическими и формальными параметрами должно быть полное совпадение по количеству, порядку следования и типу.
Начало … Операторы основной программы … Вызов подпрограммы (перечисляются фактические параметры) … Продолжение основной программы … Конец Подпрограмма Заголовок (перечисляются формальные параметры, вместо которых подставляются при вызове фактические) Тело подпрограммы …
Формальные параметры • Для каждого формального параметра в заголовке подпрограммы следует указать имя и, как правило, тип. • Имена параметров могут быть любыми, в том числе и совпадать с именами объектов программы. Необходимо лишь помнить, что в этом случае параметр основной программы с таким именем становится недоступным для непосредственного использования подпрограммой.
Пример • • Пусть, например, процедура sq осуществляет решение квадратного уравнения ax 2 + bx + c = 0. Тогда она должна иметь пять формальных параметров: для значений коэффициентов a, b, c и для результатов: x 1 и x 2. Для того, чтобы запустить процедуру в работу, необходимо к ней обратиться (ее вызвать). Вызов процедуры N производится оператором вида N(p 1, p 2, p 3, …); здесь N – имя процедуры, p 1, p 2, p 3 – фактические параметры. При вызове процедуры машина производит следующие действия. Устанавливает взаимно однозначное соответствие между фактическими и формальными параметрами, затем передает управление процедуре. После того, как процедура проработает, управление передается вызывающей программе на оператор, следующий за вызовом процедуры. Соответствующие параметры не обязательно должны быть одинаково обозначены. Описать процедуру sq можно так: sq(p, q, r, y, z); здесь p, q, r – коэффициенты квадратного уравнения, а r, y и z – корни этого уравнения. Если вызвать sq оператором sq(x 1, x 2, a, b, c), то машина воспримет x 1, x 2 и a как коэффициенты уравнения, а корни зашлет в переменные b и c.
Виды формальных параметров • Все формальные параметры можно разбить на четыре категории: • параметры-значения (эти параметры в основной программе подпрограммой не меняются!); • параметры-переменные (эти параметры передаются по ссылке, подпрограмма может изменить их значения в основной программе); • параметры-константы (используются только в версии Pascal 7. 0); • параметры-процедуры и параметры-функции.
Механизмы передачи параметров в подпрограмму • Передача параметров по значению (параметры-значения). Формальному параметру присваивается значение фактического параметра. В этом случае формальный параметр будет содержать копию значения, имеющегося в фактическом, и никакое воздействие, производимое внутри подпрограммы на формальные параметры, не отражается на параметрах фактических. • Передача параметров по ссылке (параметры-переменные). В формальный параметр помещён сам фактический параметр (путём помещения в формальный параметр ссылки на фактический). При этом любое изменение формального параметра в подпрограмме отразится на фактическом параметре — оба параметра во время вызова подпрограммы суть одно и то же. Параметры, передаваемые по ссылке, дают возможность не только передавать параметры внутрь подпрограммы, но и возвращать вычисленные значения в точку вызова.
Описание параметров-переменных • Параметр-переменная указывается в заголовке подпрограммы аналогично параметру-значению, но только перед именем параметра записывается зарезервированное слово var. • Действие слова var распространяется до ближайшей точки с запятой, т. е. в пределах одной группы. Пример procedure Max. Min(A: t. Arr; var Max, Min: Real; N: Word); • Здесь Max, Min — параметры-переменные, А и N – параметры-значения. • Тип параметров-переменных может быть любым.
Примеры Передача параметра по значению: Передача параметра по ссылке: program test; procedure udv(x: integer); begin x: =x*2; writeln(x); end; var a: integer; begin readln(a); //допустим, введем 5 udv(a); //будет выведено 10 writeln(a); // будет выведено 5! end. program test; procedure udv(var x: integer); begin x: =x*2; writeln(x); end; var a: integer; begin readln(a); //допустим, введем 5 udv(a); //будет выведено 10 writeln(a); // будет выведено 10! end. Описание формального параметра без ключевого слова var означает, что при вызове подпрограммы значение фактического параметра будет скопировано и подставлено на место формального А если мы описываем формальный параметр с ключевым словом var, то при вызове подпрограммы в качестве формального параметра будет использован сам фактический параметр
Про слово var • Слово var в заголовке подпрограммы обозначает формальные параметрыпеременные; • Внутри самой подпрограммы может быть собственный раздел описания переменных, обозначающийся словом var. В нем описываются переменные, с которой будет вестись работа внутри ТОЛЬКО ДАННОЙ подпрограммы.
Функции • Функция отличается от процедуры тем, что результат ее работы возвращается в виде значения этой функции и, следовательно, вызов функции (обращение к ней) может использоваться в выражениях: a: =sqrt(x)+sin(y); if cos(b)=0 then writeln(`Ноль!`); • Функция всегда возвращает некоторое (одно!) значение, процедура же просто выполняет некоторые действия. В частности, может присваивать значения некоторым переменным.
Синтаксис заголовка функции Function <имя функции> (<список формальных параметров>): <тип результата>; • Например: function Primer_F (A, B, C: integer): real; • В выполняемой части функции хотя бы один раз имени функции должно быть присвоено значение результата (чаще всего перед выходом из функции);
Результат функции • В языке Delphi определена стандартная переменная Result (ее не надо описывать в разделе описаний), которая является результатом, возвращаемым функцией. • Тип переменной Result автоматически устанавливается таким же, как и тип самой функции. • В конце каждой функции рекомендуется присвоить ей значение с использованием именно переменной Result.
Пример процедуры Деление и умножение одного числа на другое Program primer_P; Var // здесь описываются так называемые глобальные переменные, используемые во всей программе a, b: real; procedure multdiv(a, b: real); // в заголовке перечисляем формальные параметры Var // а потом описываем переменные, которые используются только внутри этой процедуры adiv, amult: real; begin adiv: =a/b; amult: =a*b; writeln('======'); writeln('Chastnoe ', a: 2: 2, '/', b: 2: 2, '=', adiv: 2: 2); // красиво оформляем вывод результата writeln('Proizvedenie ', a: 2: 2, '*', b: 2: 2, '=', amult: 2: 2); writeln('======'); end; begin repeat writeln(‘Введите a и b (при этом b<>0): '); readln(a, b); // считываем сразу два значения, введенные с клавиатуры последовательно until b<>0; multdiv(a, b); end.
Пример функции Возведение числа в степень Program primer_F; var a, b: real; function power(a, b: real): real; begin if (a=0) or (a=1) then result: =1 else if (a<0) then result: =1/exp(b*ln(a)) else result: =exp(b*ln(a)); end; begin writeln('Bbegume osnovanie: '); readln(a); writeln('Vvedite pokazatel: '); readln(b); writeln(power(a, b): 5: 5); // вывод результата обращения к функции readln; end.
Рекурсия • Рекурсия — такой способ организации вычислительного процесса (написания программы), при котором подпрограмма в ходе выполнения обращается сама к себе. • Для некоторых алгоритмов рекурсивное оформление подпрограммы может быть более компактным и эффективным, но следует помнить, что количество рекурсивных вызовов ограничено. • Классическим примером рекурсивной подпрограммы служит функция вычисления факториала числа.
Пример рекурсии Program primer_rekursii; var N: integer; function fact(n: integer): extended; begin repeat if n=0 then result: =1 else result: =n*fact(n-1); //вот рекурсия!!! until n>=0; end; begin writeln('enter N: '); readln(N); writeln('Result: ', fact(N)); readln; end.
Область видимости переменных • Переменные, объявленные в разделе описаний программы, доступны и внутри подпрограмм. • Переменные, объявленные в подпрограмме, доступны только в этой подпрограмме.
Область видимости и время жизни идентификаторов (переменных и т. д. ) • Переменные и прочие объекты, описания которых содержатся в подпрограмме, являются локальными и действуют только внутри этой подпрограммы. Никакой связи между ними и объектами вызывающей программы/подпрограммы, имеющими (возможно, случайно) такие же имена, нет. Они полностью независимы. • С другой стороны, в подпрограмме можно использовать идентификаторы, описанные только в вызывающей программной единице, но не в самой подпрограмме. Смысл и значение этих идентификаторов будут одинаковы и там, и там. Такие идентификаторы называются глобальными, или нелокальными. • Область действия описания конкретного идентификатора называется его областью видимости.
Избегайте глобальных переменных в подпрограммах! • Использования глобальных переменных в подпрограммах следует избегать по двум причинам: 1. Подпрограмма, использующая глобальные переменные, становится менее универсальной, чем замкнутая, «самодостаточная» подпрограмма. При ее переносе в другую программу придется тщательно проследить за обменом данными между программными единицами с помощью глобальных переменных. 2. Вторая причина связана с тем, что при использовании глобальных переменных возрастает риск ошибок, подчас трудно обнаружимых, вызванных «несанкционированным» или неучтенным изменением значения глобальной переменной в теле подпрограммы. Такие процедуры (или функции) могут иметь неожиданные побочные эффекты.
Еще о глобальных переменных • Вместе с тем, слишком большое число параметров замедляет работу программы, поэтому переменные заведомо общие в основной программе и подпрограммах целесообразно использовать как глобальные.
Вложенность подпрограмм • Если в подпрограмме описаны другие процедуры или функции, то область видимости описанных в ней переменных распространяется на вложенные подпрограммы, если только в них не описаны переменные с такими же именами.
Program X; Var i, j: integer; z: real; procedure X 1; Var i: integer; j: boolean; procedure X 2; var z: integer; procedure X 3(z: string); var k: integer; function y 4(z: string): string; • Каждый идентификатор виден в пределах того прямоугольника, в котором он описан и в прямоугольниках, содержащихся в данном. За пределами этого прямоугольника идентификатор либо неизвестен, либо имеет другое значение, тип. • Например, функция y 4 может быть вызвана лишь внутри процедур x 2 и x 3, аналогично и x 3. Переменные z в теле программы и в каждой из подпрограмм x 2, x 3, y 4 имеют абсолютно разные и независимые значения, а в x 1 видима та же переменная z, что и в теле программы. В то же время переменные i и j перекрыты в x 1 новыми определениями, а в x 2, x 3, y 4, они те же, что и в основной программе.
• Областью действия (видимости) идентификатора (переменной, константы и пр. ) называется часть программы, где он может быть использован. • Область видимости идентификаторов определяется местом их объявления в программе. Если идентификаторы допускается использовать только в рамках одной процедуры или функции, то такие идентификаторы называются локальными. Если действие идентификаторов распространяется на несколько вложенных (не менее одной) процедур и/или функций, то такие идентификаторы называются глобальными. • Продемонстрируем это следующим примером
• • • В данном примере А 0, В 0, С 0 будут глобальными для всех процедур и функций, используемых в программе. А 1, В 1, С 1 будут глобальными для всех процедур и функций, описанных внутри процедуры Р 1 (в данном случае — для процедуры Р 2), и одновременно локальными для самой процедуры Р 1. Переменные А 2, В 2, С 2, объявленные в самой внутренней процедуре Р 2, будут только локальными.
• Сформулируем правила определения области действия для идентификаторов процедур и функций: • Действуют все идентификаторы, определенные внутри процедуры/функции; • Действуют все идентификаторы окружающего контекста, если их имена отличаются от имен, объявленных внутри процедуры/функции; • Локальные идентификаторы процедуры/функции во внешнем окружении действовать не будут никогда; • В случае совпадения имен глобального и локального идентификаторов действовать будет только внутренний локальный идентификатор. • Если первые три правила поясняются рассмотренным примером, то для пояснения четвертого приведем еще один пример.
• • • Таким образом, объявление во внутренней процедуре идентификаторов, совпадающих по имени с идентификаторами внешних процедур, отменяет действие внешних идентификаторов и вводит свои локальные описания, независимо от того, совпадают они по типу, или нет. Локальные данные (идентификаторы) создаются при вызове подпрограммы и существуют только во время ее выполнения. Выделения памяти для локальных данных происходит автоматически в начале выполнения подпрограммы, а освобождение этой памяти — как только выполнение подпрограммы заканчивается. Операторы, расположенные в теле подпрограммы, могут обращаться к ее локальным данным (переменным) и изменять их значения. Однако следует помнить, что значения локальных данных существуют, пока подпрограмма работает. Как только она заканчивается, все изменения значений локальных данных, сделанные операторами подпрограммы, исчезнут вместе с освобождением памяти.
Спасибо за внимание!