#14.1 Процедуры - продпрограммы в Паскале. Объявление и использование. Область видимости, глобальные и локальные переменные
Primary tabs
Процедура -- это подпрограмма, которую можно вызывать из тела основной программы.
Пример простой процедуры:
// объявление процедуры procedure privet(); // имя процедуры begin // тело процедуры writeln('Привет Мир!'); end; begin // тело программы privet(); end.
Понятие области видимости переменной
Области видимости [переменной или иной сущности в программе] -- это все те фрагменты кода ("места" программы), из которых к данной переменной можно обратиться (напр. получить значение). (взято из Словаря программиста)
Рассмотрим два типа области видимости:
- Глобальная -- эти имена [переменных] "видны" везде в программе
- Локальная (локальная для указанной процедуры) -- эти имена "видны" только внутри подпрограммы (процедуры)
В глобальной области видимости находятся все переменные, которые мы уже умеем объявлять в секции var.
Эта секция называется "глобальной секцией объявления переменных".
Рассмотрим примеры.
Пример №1 Локальные и глобальные переменные
Процедура может обладать собственной секцией объявления переменных (локальной), например
var i: integer; // глобальная секция объявления переменных procedure chitai(); var a: integer; // локальные переменные процедуры begin writeln('Введите число:'); readln(a); writeln('a=', a); end; begin // тело программы chitai(); i:=1; writeln(i); end.
Глобальных переменных в программе конечно может и не быть:
procedure chitai(); var a: integer; // локальные переменные процедуры begin writeln('Введите число:'); readln(a); writeln('a=', a); end; begin // тело программы chitai(); end.
Пример №2 Обращение к локальной переменной из процедуры
Глобальные переменные "видны" во всех участках кода и мы обращаться с ним из тела процедуры:
var i: integer; // глобальная секция объявления переменных procedure pishi(); var a: integer; // локальные переменные процедуры begin writeln('Введите число:'); readln(a); writeln('a=', a); writeln('i=', i); end; begin // тело программы i:=1; pishi(); end.
Почему не стоит обращаться к глобальным переменным из подпрограммы
Использование глобальных переменных - плохой подход, т.к. он усложняет перенос процедуры (и любой другой подпрограммы) в другую программу, рассмотрим пример - пусть у есть
Программа 1, в которой реализована процедура:
var a: integer; // глобальная секция procedure pishi(); begin writeln('Введите число:'); readln(a); writeln('a=', a); end; begin // тело программы pishi(); end.
И Программа 2:
var b: integer; // глобальная секция begin // тело программы writeln('Введите число:'); readln(b); writeln('a=', b); end.
-- по сути это программа делает то же самое, что и программа 1, а значит мы могли переиспользовать код процедуры и добиться того же результата, т.е. перенести код процедуры в программу 2 и выполнить ее вызов:
var b: integer; // глобальная секция procedure pishi(); // скопировали begin writeln('Введите число:'); readln(a); // переменной а нет в глобальной секции!! writeln('a=', a); end; begin // тело программы pishi(); // заменяем код на идентичный вызов процедуры end.
-- запустим и получим ошибку о том, что переменная a не определена, что логично - ведь ее нет в глобальной области видимости.
Как решить проблему?
Есть два способа:
- 1) Объявлять локальные переменные, если они нужны только внутри тела процедуры
- 2) Передавать на вход (этот вариант рассмотрим ниже в этом уроке)
Перепишем нашу так, чтобы она стала легко переносимой и не зависящей от глобальных имен конкретной программы, для этого сделаем единственную переменную с которой она работает локальной:
procedure pishi(); var a: integer; // "приземляем" имя в локальной секции begin writeln('Введите число:'); readln(a); writeln('a=', a); end;
-- т.е. мы добавили локальной определение имени, чтобы процедура не лезла в глобальное пространство имен в попытке найти там нужное имя (ведь там может и не оказаться, как в пример с переносом кода выше)
Этот код легко перенести, он игнорирует глобальное пространство т.к. не обращается к нему, Программа 2 теперь будет выглядеть так:
var b: integer; // глобальная секция procedure pishi(); var a: integer; // "приземляем" имя в локальной секции begin writeln('Введите число:'); readln(a); writeln('a=', a); end; begin // тело программы pishi(); // заменяем код на идентичный вызов процедуры end.
Ну а Программа 1, соответственно, так:
var a: integer; // глобальная секция procedure pishi(); var a: integer; // "приземляем" имя в локальной секции begin writeln('Введите число:'); readln(a); writeln('a=', a); end; begin // тело программы pishi(); end.
-- глобальная переменная здесь не нужна, но стоит отметить что глобальная а и локальная а - могут иметь разные значения, все зависит от того из какого участка кода мы обращаемся к данному имени, рассмотрим пример:
var a: integer; // глобальная секция procedure pishi(); var a: integer; // "приземляем" имя в локальной секции begin a:=3; // обращение к а (на запись) writeln('a=', a); // обращение к а (на чтение) end; begin // тело программы a:=2; // обращение к а (на запись) pishi(); writeln(); writeln('a=', a); // тоже обращение к а на чтение) end.
-- запустите код, и увидите что присваивания в локальной видимости фактически не затрагивают глобальность область видимости, на то, что используется одно и то же имя.
Это примерно то же самое, что в разных классах школы могут быть два ребенка-тезки с именем "Коля", в каждом классе одноклассники под именем будут подразумевать "своего" Колю, это пример локальной области видимости. Т.е. в зависимости от "места", то что подразумевается под одним и тем же именем оказывается различно.
Процедуры и функции принимают какие-то значения "на вход" -- это те данные, с которыми процедура или функция будут работать.
Понятие сигнатуры подпрограммы
Сигнатура -- характеристика подпрограммы, которая говорит о том, что минимально нужно знать, чтобы использовать данную подпрограмму, в общем случае в список таких сведений входят:
- название подпрограммы
- параметры, принимаемые "на вход" и их типы (причем подряд передаваемых параметров часто важен!)
- тип возвращаемого значения (в Паскале у процедур возвращаемого значения нет, оно есть только у функций, про которые мы поговорим в следующих уроках)
Вызов процедуры и её сигнатура
Сигнатура процедуры определяется:
- Именем процедуры
- Числом, типом входных переменных и порядком их следования
Например, рассмотрим реализацию процедуры $sum1()$, которая складывает два числа и выводит сумму на экран:
procedure sum1(x, y: integer); // начало объявления процедуры begin write(x + y); end; // конец тела процедуры
Иллюстрацией к сигнатуре этой процедуры служит её заголовок:
procedure sum1(x, y: integer);
-- где фактически написано, что для нормальной работы этой процедуре требуется получить (а программисту во внешнем коде передать) два значения целого типа, рассмотрим пример вызова этой процедуры с передачей параметров:
procedure sum1(x, y: integer); // начало объявления процедуры begin write(x + y); end; // конец тела процедуры begin // начало тела программы sum1(5, 7); // вызов процедуры end.
Передача параметров в подпрограмму - процедуру. Получение значений на "вход"
Мы можем передавать параметры "на выход" процедуре и обращаться к ним в ее теле:
procedure pishi(a: integer); begin writeln('a=', a); end; begin // тело программы pishi(5); end.
Передавать можно любые значения - литералы (как в примере выше), выражения, переменные.
Пример с передачей процедуре переменной:
var b: integer; // "глобальные" переменные procedure pishi(a: integer); begin writeln('a=', a); end; begin // тело программы b := 7; pishi(b); // вызываем со значением b writeln('Конец!'); end.
Процедура может использовать одновременно как входящие аргументы (переменные, переданные ей при вызове) так и локальные, например:
var b: integer; // "глобальные" переменные procedure pishiSummu(a: integer; comment: string); var h: integer; begin h := 5; writeln(comment, ':'); writeln('Summa=', h+a); end; begin // тело программы b := 7; pishiSummu(b, 'Сумма входящего значения и локального'); writeln('Конец!'); end.
ПРИМЕЧАНИЕ: добавить примеры вызова из цикла.
Передача параметров в подпрограмму по ссылке и по значению
Параметры в подпрограмму (в том числе в процедуру) могут быть переданы:
- по значению - в этом случае, значение копируется для подпрограммы и не изменяется в области видимости, в которой подпрограмме была вызвана с данным параметром
- по ссылке - в этом случае значение не копируется и изменяется в области видимости, в которой процедура была вызвана с данным параметром, в случае параметр меняется в подпрограмме
Задачи для самостоятельного решения
- Напишите процедуру, которая просит пользователя ввести три числа, и потом выводит их в обратном порядке
Примечание: если не получается решить или для лучшего понимания см. этот разбор решения.
- Напишите процедуру, которая получает на вход два целых числа и выводит на экран то, которое больше.
Примечание: если не получается решить или для лучшего понимания см. этот разбор решения
-
У вас есть код:
var b: integer; procedure pishi(); var a: integer; begin a:=4; writeln(a); b:=2; writeln(b); end; begin // тело программы b:=3; pishi(); writeln(b); end.
-- эта программа в конечном итоге присваивает и выводит на экран 3 значения.
Задача: Уберите зависимость процедуры от глобальной области видимости (т.е. процедура более не должна обращаться к глобальной области видимости), при этом пусть для нового кода выполняются все требования из списка:
- вывод программы останется тем же
- процедура, как и раньше работает с двумя переменными a и b, но обе должны быть локальными
- процедура не должна принимать аргументы, как и раньше
- а тело программы как и раньше с 1 глобальной переменной
- Постарайтесь максимально сохранить использующиеся имена переменных.
-
Напишите процедуру, которая получает на вход три целых числа и выводит на экран их сумму.
Примечание: если не получается решить или для лучшего понимания см. этот разбор решения
-
У вас есть код:
var b: integer; procedure p2(); var a: integer; begin a:=4; writeln('a=', a); writeln('b=', b); end; begin writeln('Введите значение b:'); readln(b); p2(); end.
-- перепишите его так, чтобы процедура не зависела от глобальное переменной b, а получала ее на вход, при этом определяется переменная b (запрос на ввод значения и readln) пусть как и раньше в теле основной программы.
Примечание: если не получается решить или для лучшего понимания см. этот разбор решения
- Пользователь по запросу программы вводит в цикле целые положительные числа, до тех пор пока не введет число большее 30. В ответ на каждое введенное пользователем число выводите все числа от 1 до этого введенного числа $m$.
При этом:- за выводит чисел от 1 до $m должна отвечать процедура
- получение значения должно проходить в теле основной программы
- Составьте программу, которая выводит на экран прямоугольный флаг $N \times M$ вида (используйте циклы repeat):
- - - - - - - - - - - - - - - - - - - - - - - -
- для вывода очередной строки используйте процедуру.
- Напишите процедуру, которая выводит на экран максимальное из трех переданных целых чисел.
- Log in to post comments
- 2461 reads