Процедуры и функции. При решении сложных объемных задач часто целесообразно разбивать их на более простые. Метод последовательной детализации позволяет составить алгоритм из действий, которые, не являясь простыми, сами представляют собой достаточно самостоятельные алгоритмы. В этом случае говорят о вспомогательных алгоритмах или подпрограммах. Использование подпрограмм позволяет сделать основную программу более наглядной, понятной, а в случае, когда одна и та же последовательность команд встречается в программе несколько раз, даже более короткой и эффективной.
В языке Паскаль существует два вида подпрограмм: процедуры и функции, определяемые программистом. Процедурой в Паскале называется именованная последовательность инструкций, реализующая некоторое действие. Функция отличается от процедуры тем, что она должна обязательно выработать значение определенного типа.
Процедуры и функции, используемые в программе, должны быть соответствующим образом описаны до первого их упоминания. Вызов процедуры или функции производится по их имени.
Подпрограммы в языке Паскаль могут иметь параметры (значения, передаваемые в процедуру или функцию в качестве аргументов). При описании указываются так называемые формальные параметры (имена, под которыми будут фигурировать передаваемые данные внутри подпрограммы) и их типы. При вызове подпрограммы вместе с ее именем должны быть заданы все необходимые параметры в том порядке, в котором они находятся в описании. Значения, указываемые при вызове подпрограммы, называются фактическими параметрами.
Раздел описаний может иметь такие же подразделы, как и раздел описаний основной программы (описание процедур и функций - в том числе). Однако все описанные здесь объекты "видимы" лишь в этой процедуре. Они здесь локальны также, как и имена формальных параметров. Объекты, описанные ранее в разделе описаний основной программы и не переопределенные в процедуре, называются глобальными для этой подпрограммы и доступны для использования.
Легко заметить схожесть структуры программы целиком и любой из ее процедур. Действительно, ведь и процедура и основная программа реализуют некий алгоритм, просто процедура не дает решения всей задачи. Отличие в заголовке и в знаке после End.
Формат описания функции: Function <Имя функции> (<Имя форм. параметра 1>:<Тип>; < Имя форм. параметра 2>:<Тип>) : <Тип результата>;
<Раздел описаний>
Begin <Тело функции>
End;
В теле функции обязательно должна быть хотя бы команда присвоения такого вида: <Имя функции>:=<Выражение>;
Указанное выражение должно приводить к значению того же типа, что и тип результата функции, описанный выше.
Вызов процедуры представляет в программе самостоятельную инструкцию: <Имя процедуры>(<Фактический параметр 1>, < Фактический параметр 2>);
Типы фактических параметров должны быть такими же, что и у соответствующих им формальных.
Вызов функции должен входить в выражение. При вычислении значения такого выражения функция будет вызвана, действия, находящиеся в ее теле, будут выполнены, в выражение будет подставлено значение результата функции.
Приведем простейший пример использования подпрограммы.
Пример. Найти максимальное из трех введенных чисел". Для решения воспользуемся описанием функции, принимающей значение максимального из двух чисел, которые передаются в нее в виде параметров.
Program Fn; Var A,B,C :Real; Function Max(A,B:Real):Real;{Описываем функцию Max с формальными} Begin {параметрами A и B, которая принимает }
If A>B Then Max:=A {значение максимального из них } Else Max:=B {Здесь A и B - локальные переменные }
End; Begin
Writeln('Введите три числа'); Readln(A,B,C); Writeln('Максимальным из всех является ', Max(Max(A,B),C))
End.
Существует два способа передачи фактических параметров в подпрограмму: по значению и по ссылке. В первом случае значение переменной-фактического параметра при вызове подпрограммы присваивается локальной переменной, являющейся формальным параметром подпрограммы. Что бы потом ни происходило с локальной переменной, это никак не отразится на соответствующей глобальной. Если требуется произвести в подпрограмме действия над самими переменными, указанными в качестве фактических параметров, то используется второй способ. Происходит следующее: при обращении к подпрограмме не происходит формирования локальной переменной-формального параметра. При этом на время выполнения подпрограммы имя этой локальной переменной будет указывать на ту же область памяти, что и имя соответствующей глобальной переменной. Если в этом случае изменить локальную переменную, изменятся данные и в глобальной.
Передача параметров по ссылке отличается тем, что при описании подпрограммы перед именем переменной-формального параметра ставится служебное слово Var. Теперь использование в качестве фактических параметров выражений или непосредственных значений уже не допускается - они должны быть именами переменных.
Пример. Расположить в порядке неубывания три целых числа.
Program Pr; Var S1,S2,S3 :Integer;
Procedure Swap(Var A,B: Integer);{Процедура Swap с параметрами-переменными} Var C : Integer; {C - независимая локальная переменная} Begin C:=A; A:=B; B:=C {Меняем местами содержимое A и B} End; Begin
Writeln('Введите три числа'); Readln(S1,S2,S3); If S1>S2 Then Swap(S1,S2); If S2>S3 Then Swap(S2,S3); If S1>S2 Then Swap(S1,S2); Writeln('Числа в порядке неубывания:V',S1,S2,S3)
End.
Порядок работы с файлами в Паскале.В прикладных программах, как правило, имеется большое число входных и выходных данных, причем часто возникает необходимость передачи данных из одной программы в другую. Поэтому данные хранятся в файлах и при необходимости считываются, а также записываются в файлы операторами программы. Файлом называется именованная область внешней памяти ЭВМ, содержащая различные данные. Доступ к данным в файле может быть прямым или последовательным в зависимости от типа файла. Рассмотрим работу с данными текстовых файлов.
Текстовые файлы представляют совокупность строк переменной длины с последовательным доступом к данным, т. е. данные записываются на диск и считываются только последовательно. Информация в текстовых файлах хранится в символьном (текстовом) виде. При записи числовых или логических значений происходит автоматическое преобразование данных в символьный тип, а при считывании данные автоматически преобразуются в машинные коды. При записи в файл данные записываются подряд, а управляющие символы (перевод строки, конец файла) устанавливаются автоматически оператором Writeln. Управляющие символы работают при просмотре/редактировании файла на экране или при печати, но при этом, как правило, не показываются.
Для каждого файла при чтении или записи информации есть такое понятие, как текущее положение в файле. Текущее положение в файле это то положение, в котором на данный момент идет обработка информации. То есть вся информация разбиваеся на одинаковые по размеру блоки, и далее осуществляется работа с этими блоками. Например если файл текстовый - то по буквам. Если файл типизированный - то по записям. Если нетипизированный - то по группам байт (нетипизированным записям). В большинстве случаев за текущим положением следить нет необходимости. То есть, после чтения из файла текущее положение автоматически изменяется на следующее. И так можно читать последовательно каждую запись, не заботясь о текущем положении.
Текущее положение может быть началом файла, или самым концом файла. Если текущее положение уже конец файла, то последующее чтение из него ни к чему не приведет. А вот запись в него увеличит размер файла на записываемый кусок информации, после чего текущее положение изменится, и будет опять указывать в конец файла.
Основные действия, реализуемые при работе с файлами.
1. Описать тип файловой переменной. Например, переменная f в зависимости от типа файла может быть описана так:
var f : file of <тип>; {компонентный файл}
или
var f : text; {текстовый файл}
или
var f : file; {бестиповый файл}
Тип file описывает линейную последовательность компонент, указанного типа. Тип файла text означает файл, состоящий из строк символов.
2. Связать файловой переменной с именем файла - команда Assign(f). Одновременно в программе может быть открыто несколько десятков файлов, каждый из которых должен иметь свою файловую переменную.
3. Открыть файл командой Rewrite(f) для записи во вновь создаваемый файл или Reset(f) для чтения/записи уже имеющегося файла. Если открывается существующий текстовый файл, то используем команду Append(f).
4. Осуществить чтение или запись в файл - команды Read или Write соответственно (для построчной работы с текстовыми файлами можно использовать соответственно ReadLn или WriteLn). Например, команда записи в файл выглядит так: Write(f, а), где f - файловая переменная; а - переменная любого типа (byte, real, string и т. д., соответствующая типу файла). При обращении к командам Read/Write позиция чтения/записи в файле автоматически увеличивается на единицу.
5. Закрыть файл - команда Close(f).
Пример программы, демонстрирующей возможные действия с файлом:
Program Files;
Var
a:array[1..10] of real;
f: text;
i: integer;
Begin
Assign(f, 'h:\TEST.TXT'); { связывание файловой переменной f c именем файла 'h:\TEST.TXT' }
Rewrite(f); { Создание нового файла }
WriteLn(f,'Вектор a');
for i:=1 to 10 do
begin
a[i]:=random*10;
Write(f,a[i]:6:2,' '); { Запись массива a в файл }
end;
Close(f); { Закрытие файла }
Reset(f); { Открытие файл для чтения}
Readln(f);
for i:=1 to 10 do
Read(f,a[i]); { Cчитывание массива a из файла }
Close(f); { Закрытие файла}
End.
Ниже приведено описание процедур и функций Паскаля, работающих с файлами.
1. Процедура Append(var f : Text); Открывает существующий текстовый файл f для дополнения.
2. Процедура Assign(var f; name : String); Связывает внешний файл с именем name и переменную файлового типа f. Все дальнейшие операции с переменной f будут выполняться с указанным внешним файлом.
3. Процедура Close(var f); Закрывает открытый файл, связанный с переменной f.
4. Функция Eof(var f); типа Boolean; Показывает значение Истина (True) при наличии признака конца файла для типизированных или нетипизированных файлов, указываемых файловой переменной f.
5. Функция FilePos(var f); типа Longint; Показывает текущую позицию в файле, указываемом переменной f. Если эта позиция в конце файла, то функция возвращает значение, равное длине файла, а если в начале файла, значение 0.
6. Функция FileSize(var f); типа Longint; Показывает текущий размер файла f в байтах. Если файл пуст, то 0.
7. Процедура Reset(var f [ : file; RecSize : Word ] ); Открытие существующего файла. Имя внешнего файла, связанного с f, должно быть ранее определено. Необязательный параметр RecSize: размер записи нетипизированного файла.
8. Процедура Rewrite(var f : file [;RecSize : Word ] ); Создает и открывает новый файл. Если такой файл уже есть, то он удаляется и создается новый с тем же именем.
9. Процедура Seek(var f; n : Longint); Перемещает текущую позицию файла к элементу с номером n (не может быть использована для текстовых файлов, первая позиция равна 0).
10. Процедура Truncate(var f); Усекает размер файла f до текущей позиции в файле.
Задание на работу
Разработать программу по заданию, соответствующему варианту.
Таблица 14 – Варианты заданий
Номер варианта
Задание
Считать случайную матрицу A=[5X5] из файла, созданного с помощью процедуры random, матрицу передать в процедуру, в ней с помощью этой матрицы создать 2 новых матрицы Symm= A+At и AntiSymm= A-At. Эти 2 новые матрицы вернуть в главную программу и распечатать по строкам.
Считать случайную матрицу A=[5X5] из файла, созданного с помощью процедуры random, матрицу передать в процедуру, в ней для каждой строки матрицы найти среднее значение Si=Σj Aij /N и средне-квадратичное отклонение Сi=Σj (Aij –Si)2 /N. Эти 2 новых вектора вернуть в главную программу и распечатать.
Считать случайный массив A=[10] из файла, созданного с помощью процедуры random и сдвига на -0.5, массив передать в функцию, в нем подсчитать число чередований знака в массиве (т.е переходов с плюса на минус и с минуса на плюс) и вернуть в главную программу и распечатать.
Считать случайный массив A=[10] из файла, созданного с помощью процедуры random и сдвига на -0.5, массив передать в процедуру, в ней упорядочить массив по возрастанию ( с помощью двойного цикла) и вернуть в главную программу и распечатать.
Считать случайную матрицу A=[5X5] из файла, созданного с помощью процедуры random, матрицу передать в процедуру, в ней для каждой строки матрицы найти разность максимального и минимального элемента строки и вернуть этот вектор в главную программу и распечатать.
Считать случайный массив A=[10] из файла, созданного с помощью процедуры random и сдвига на -0.5, массив передать в процедуру, в нем выделить новый массив B, в котором останутся элементы А, меньшие по модулю 0.3 и вернуть B в главную программу и распечатать.
Считать случайную матрицу A=[5X5] из файла, созданного с помощью процедуры random, матрицу передать в процедуру, в ней для каждой строки матрицы найти среднее значение Si=Σj Aij /N и вычислить матрицу B=exp(Aij- Si ). Эту матрицу B вернуть в главную программу и распечатать по строкам.
Считать случайную матрицу A=[5X5] из файла, созданного с помощью процедуры random, матрицу передать в процедуру, в ней для каждой строки матрицы найти среднее значение Si=Σj Aij /N и вычислить матрицу Bij=(Si - Sj). Эту матрицу B вернуть в главную программу и распечатать по строкам.
Считать случайный массив A=[10] из файла, созданного с помощью процедуры random и сдвига на -0.5, массив передать в процедуру, в ней создать новый массив В, совпадающий с А, но в котором 4 минимальных элемента старого массива стоят на первых местах, этот массив вернуть в главную программу и распечатать оба массива .
Считать случайный массив A=[10] из файла, созданного с помощью процедуры random, массив передать в функцию, в нем подсчитать целочисленный массив В, равный числу элементов А, лежащих между 0 и 0.1, 0.1 и 0.2, 0.2 и 0.3 и т.д число чередований знака в массиве (т.е переходов с плюса на минус и с минуса на плюс) и вернуть В в главную программу и распечатать.