Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
osnovy_programmirovanija_v_srede_lazarus.pdf
Скачиваний:
182
Добавлен:
18.03.2015
Размер:
6.53 Mб
Скачать

3.1 Общая структура Паскаль – программы

____________________________________________________________________

и позволяет передать управление оператору с меткой <Метка>.

Программа, содержащая метки обычно плохо читается и, как правило, яв-

ляется не структурированной. Вполне можно писать программы вообще не ис-

пользуя метки. Итак, забыли про метки и поехали дальше!

3.1.1 Процедуры и функции

При разработке больших программ почти всегда появляются часто повто-

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

Подпрограммы делятся на процедуры и функции. Текст процедуры или функции записывается в разделе описаний, после описания переменных. В

дальнейшем для того, чтобы использовать эту процедуру или функцию доста-

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

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

ляются точкой с запятой.

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

3.1.1.1 Структура процедуры

procedure <имя процедуры>[(параметры)];

label

< Метки >;

142

Глава 3 Более сложные элементы языка

____________________________________________________________________

const

< Константы >; type

< Новые типы данных >; var

<Описание локальных переменных >;

<Описание внутренних процедур >;

<Описание внутренних функций >;

begin

< Тело процедуры >; end;

Параметры, указанные в заголовке называются формальными параметра-

ми. Для вызова процедуры необходимо просто указать ее имя и параметры (ес-

ли они имеются). Параметры, указанные при вызове процедуры называются фактическими параметрами.

3.1.1.2. Структура функции

function <имя функции>[(параметры)]:тип функции; label

<Метки >; const

<Константы >;

type

<Новые типы данных >;

var

<Описание локальных переменных >;

<Описание внутренних процедур >;

<Описание внутренних функций >;

143

3.1 Общая структура Паскаль – программы

____________________________________________________________________

begin

< Тело функции >;

end;

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

димо указать ее имя и фактические параметры (при их наличии). Причем имя функции можно указывать в выражениях!

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

ленным значением.

В последнее время входит в моду присваивать значение внутри функции не имени функции, а системной переменной Result.

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

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

мание логики работы программы.

3.1.1.3 Глобальные и локальные переменные

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

ред ее использованием должен быть описан в разделе описаний. При этом у ка-

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

ласть видимости, где они могут использоваться. Если объект описан в подпро-

грамме, то доступ к ней из вызывающей программы невозможен. Этот объект является локальным по отношению к подпрограмме, где он описан, т.е. "не ви-

144

Глава 3 Более сложные элементы языка

____________________________________________________________________

дим" в вызывающей программе. Такие переменные, константы, функции и про-

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

вающей программе, доступны вызываемым подпрограммам, т.е. "видимы" им.

Такие объекты называются глобальными.

Рассмотрим пример, чтобы глубже понять вышесказанное:

program console_app; {$mode objfpc}{$H+} uses

CRT, FileUtil; var

x: integer; // Глобальная переменная

procedure local_global; // процедура без параметров begin

x:= 25; // Глобальная переменная х доступна процедуре writeln(UTF8ToConsole('Значение переменной x')); writeln(UTF8ToConsole('внутри процедуры = '), x);

end; // конец процедуры

begin // начало главной программы

x := 1;

writeln(UTF8ToConsole('Глобальная переменная x')); writeln(UTF8ToConsole('до вызова процедуры = '), x); local_global; // вызов процедуры writeln(UTF8ToConsole('Глобальная переменная x')); writeln(UTF8ToConsole('после вызова процедуры = '), x); writeln(UTF8ToConsole('Нажмите любую клавишу'));

readkey;

end.

145

3.1 Общая структура Паскаль – программы

____________________________________________________________________

Как видим, процедура изменила значение глобальной переменной. Следует иметь в виду, что переменная, являющаяся локальной в данной подпрограмме,

становится глобальной для всех подпрограмм низшего уровня. Рассмотрим пример:

program console_app; {$mode objfpc}{$H+} uses

CRT, FileUtil; var

x: integer; // глобальная переменная

procedure local_global; // процедура без параметров var

y: integer; // Локальная переменная

procedure A; // Процедура внутри процедуры local_global begin

y:= 100; // Внутри процедуры А переменная y является глобальной writeln(UTF8ToConsole('В процедуре А y= '), y);

end; // конец вложенной процедуры

begin

x:= 25; y:= 0;

A; // вызов процедуры низшего уровня writeln(UTF8ToConsole('После вызова процедуры А y= '), y);

end; // конец процедуры

begin

// начало главной программы

x:=

1;

writeln(UTF8ToConsole('Глобальная переменная x')); writeln(UTF8ToConsole('до вызова процедуры равна '), x);

146

Глава 3 Более сложные элементы языка

____________________________________________________________________

local_global; // вызов процедуры

//y:=1; если убрать знак комментария, компилятор выдаст ошибку,

//A; т.к. локальные объекты невидимы для главной программы

writeln(UTF8ToConsole('Глобальная переменная x')); writeln(UTF8ToConsole('после вызова процедуры равна '), x); writeln(UTF8ToConsole('Нажмите любую клавишу'));

readkey;

end.

Переменная y является локальной в процедуре local_global, в то же время она доступна процедуре А, т.е. для нее она является глобальной.

Обратите внимание, что локальные объекты недоступны вызывающей про-

грамме. Таким образом, из главной программы нельзя вызвать процедуру А и

нельзя изменить значение переменной y. Главная программа просто не знает об их существовании! Процедура local_global выступает для главной про-

граммы "черным ящиком". Для обмена данными между вызывающей програм-

мой и подпрограммой не стоит использовать глобальные переменные. Для это-

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

дующем разделе.

Использование глобальных переменных может привести к трудноулови-

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

ходимости получая от вызывающей программы данные через параметры и так-

же через параметры передавая результаты своей работы. Если это функция, то она должна возвращать единственное значение через свое имя.

Почему локальные переменные "невидимы" вызывающей программе? Де-

ло в том, что локальным переменным память распределяется по-другому, чем

147

3.1 Общая структура Паскаль – программы

____________________________________________________________________

глобальным переменным. Память для глобальных переменных выделяется ста-

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

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

ся в стеке. После завершения работы подпрограммы, память, отведенная для нее, автоматически освобождается и может быть распределена уже для другой подпрограммы.

Есть еще один тип переменных, которые по существу являются локальны-

ми, но память им выделяется в сегменте данных. Это так называемые статиче-

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

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

В Паскале статической переменной служит так называемая типизирован-

ная константа. Ее описание имеет вид:

const

Константа: Тип = Значение;

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

грамме можно изменять (только не в Delphi! Там типизированная константа яв-

ляется "настоящей" константой).

Пример.

program project1; {$mode objfpc}{$H+} uses

CRT, FileUtil;

148

Глава 3 Более сложные элементы языка

____________________________________________________________________

procedure static_var; // процедура

const x: integer = 0;

begin

writeln(UTF8ToConsole('До изменения x= '), x);

x:= х + 25;

writeln(UTF8ToConsole('После изменения x= '), x);

end; // конец процедуры

begin

writeln(UTF8ToConsole('Изменение статической переменной x'));

writeln(UTF8ToConsole('внутри процедуры после первого вызова'));

static_var;

writeln(UTF8ToConsole('Изменение статической переменной x'));

writeln(UTF8ToConsole('внутри процедуры после второго вызова'));

static_var;

writeln(UTF8ToConsole('Нажмите любую клавишу'));

readkey;

end.

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

ным 25. После второго вызова х=50, т.е. статическая переменная сохранила свое значение 25 после первого вызова процедуры.

Имена локальных переменных в подпрограмме могут совпадать с глобаль-

ными именами вызывающей программы. В этом случае при входе в подпро-

грамму доступна только локальная переменная, а глобальная становится недос-

тупной, например:

program console_app;

{$mode objfpc}{$H+}

uses

149

3.1 Общая структура Паскаль – программы

____________________________________________________________________

CRT, FileUtil; var

x: integer; // Глобальная переменная

procedure local_global; // процедура без параметров var

x: integer; // Локальная переменная с тем же именем begin

x:= 25;

writeln(UTF8ToConsole('Локальная переменная x= '), x); end; // конец процедуры

begin // начало главной программы x:= 1;

writeln(UTF8ToConsole('Значение глобальной переменной x)); writeln(UTF8ToConsole(' до вызова процедуры '), x);

local_global; // вызов процедуры

writeln(UTF8ToConsole('Значение глобальной переменной x)); writeln(UTF8ToConsole(' после вызова процедуры '), x); writeln(UTF8ToConsole('Нажмите любую клавишу'));

readkey;

end.

Мы видим, что значение глобальной переменной не изменилось. Локаль-

ная переменная ―перекрыла‖ глобальную и оператор присваивания

x:= 25;

в процедуре присвоило значение 25 совсем другой переменной, хотя и с тем же именем х.

150

Глава 3 Более сложные элементы языка

____________________________________________________________________

Таким образом, одноименные глобальные и локальные переменные - это разные переменные. Любое обращение к таким переменным в теле подпро-

граммы трактуется как обращение к локальным переменным, т. е. глобальные переменные в этом случае попросту недоступны.

Пример использования функции.

Вычислить значение y sin x путем разложения sin x в ряд Тейлора с точ-

ностью 10 3 , x [0,1], x 0.1 Вычисление оформить в виде функции.

Вычисленное значение sin x для каждого x сравнить с "точным" значением пу-

тем применения стандартной функции Паскаля sin(x).

Напомню, что мы уже писали эту программу (см. 2.1.26), но без примене-

ния функций. Разложение sin x в ряд Тейлора имеет вид:

 

x3

 

x5

x7

sin x x

 

 

 

 

 

....

3!

5!

 

7!

 

 

 

Функцию, которая

вычисляет sinx по данному ряду, назовем

No_standard_sin(x).

program sinus_fun; {$mode objfpc}{$H+} uses

CRT, FileUtil;

var

x, y, y1, dx:real;// глобальные переменные, доступны функции

function No_standard_sin (x: real): real; var

eps, s, t: real; // локальные переменные, недоступны

n: integer;

// вызывающей программе

begin

 

s:= x;

 

t:= x;

 

151

3.1 Общая структура Паскаль – программы

____________________________________________________________________

n:= 2; eps:= 1e-7; repeat

t:= -t * sqr(x)/(n * (n + 1)); s:= s + t;

n:= n + 2;

until abs(t) < eps;

No_standard_sin:= s; // возврат значения функции

//Result:= s; // можно и так end;

begin x:= 0;

dx:= 0.2;

writeln(UTF8ToConsole('Значения синуса')); writeln(UTF8ToConsole('моя функции, стандартная функции')); while x <= 1 do

begin

y:= No_standard_sin(x);// вызов моей функции y1:= sin(x); // вызов стандартной функции writeln(' ', y:0:7,' ', y1:0:7); x:= x + dx;

end;

writeln(UTF8ToConsole('Нажмите любую клавишу')); readkey;

end.

Пример.

Вспомним пример из 2.2.2. вычисления интеграла по формуле Симпсона.

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

152

Глава 3 Более сложные элементы языка

____________________________________________________________________

ции в виде функции, а вычисление интеграла в виде процедуры:

program integral; {$mode objfpc}{$H+} uses

CRT, FileUtil; var

a, b, eps: real;

function Fx(x: real): real; // Подынтегральная функция

{Если потребуется вычислить интеграл для другой функции,

достаточно поменять только один оператор}

begin

Fx:= sin(x); // Для другой функции меняем здесь

end;

{ Процедура вычисления интеграла по формуле Симпсона методом двойного пересчета}

procedure Simpson(a, b, eps: real); var

x, h, s, s1: real; n, k: integer;

begin

k:= 0; // при первом вычислении интеграла k=0

n:= 4; // начальное число точек разбиения интервала (a,b) h:= (b - a)/n; // шаг вычисления подынтегральной функции while true do

begin x:= a;

153

3.1 Общая структура Паскаль – программы

____________________________________________________________________

x:= x + h; s:= 0;

while x < (b-h) do begin

s:= s + Fx(x) + 2 * Fx(x + h); x:= x + 2 * h;

end;

s:= 2 * s;

s:= (h/3) * (Fx(a) + 2 * Fx(b) + s); if k = 0

then begin

k:= 1; s1:= s; h:= h/2; continue;

end else

if abs(s1 - s) > eps then begin

s1:= s; h:= h/2; continue;

end else

break;

end;

writeln(UTF8ToConsole('Значение интеграла s= '), s:0:4);

end; // конец процедуры

154

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]