SetWindowSize(500,500); // Эта процедура описана в GraphABC
Triangle (100,200,400,300,250,150); // Эта процедура описана в MyGraph
Triangle(10,20,30,40,50,10);
end.
Модули могут содержать неограниченное число процедур, функций, а также описаний глобальных переменных, констант (об этом позже).
Задание 10
2. Сформируйте модуль с вашими собственными графическими процедурами (5 баллов)
- 30 -
Тема №11. Способ передачи параметров
Параметры-значения и параметры-переменные
Каким образом подпрограмма может вернуть главной программе какую-либо информацию?
До сих пор это могла делать только подпрограмма-функция, возвращая через свое имя только одно значение. А как поступить, если надо вернуть из подпрограммы несколько значений?
Для примера напишем подпрограмму, которая должна вычислить длину окружности
( L = 2πr ) и площадь круга ( S = πr2) по заданному радиусу.
Program ProcUse;
Uses CRT;
// вычисление длины окружности и площади круга
Procedure Pr(R,L,S:real);
begin
L:=2*PI*R;
S:=PI*sqr(R);
end;
// ГЛАВНАЯ ПРОГРАММА
var rad, len, area : real;
begin
write('Введите радиус '); readln(rad);
Pr(rad, len, area);
writeln('Длина окружности ', len);
writeln('Площадь круга ', area);
end.
Попробуйте выполнить данную программу. Вы обнаружите странный результат: какое бы значение радиуса вы не вводили, результат будет один и тот же: длина окружности и площадь круга будут равны 0! В чем дело?
Оказывается тот способ передачи параметров подпрограмме, который мы использовали не подходит для решения нашей задачи. Используемый до сих пор способ называется передача параметров по значению. Суть его заключается в том, что подпрограмма создает копии параметров (в другой терминологии – локальные переменные подпрограммы), в которые помещаются значения, заданные в фактических параметрах в главной программе.
Т.е. по смыслу такие параметры являются входными, т.е. предназначенными для передачи информации из главной программы в подпрограмму, но не наоборот. Однако этот подход имеет тот плюс, что подпрограмма гарантирует, что она не изменит фактические параметры.
- 31 -
Второй способ называется передача параметров по ссылке. Изменим заголовок процедуры Pr на следующий:
Procedure Pr(R: real; var L,S:real);
Обратите внимание на появившееся ключевое слово var. Оно говорит о том, что два последних параметра процедуры будут являться изменяемыми. Для таких параметров используется другой способ сопоставления с фактическими (передаются на самом деле адреса параметров). В связи с этим необходимо запомнить, что в качестве формальных параметров, соответствующих параметрам переменным, могут использоваться только переменные, но не константы! Т.е. вызов Pr(5,6,7) ошибочен, возможно, лишь Pr(5,a,b), где a и b – вещественные переменные. Первый параметр мы оставили, как и раньше, обычным параметром, передаваемым по значению.
Выполним теперь программу. Работает!
Задание 11
1. Напишите процедуру с двумя целочисленными параметрами, которая бы меняла местами их значения. Проверьте ее работу.
(3 балла) 2. Напишите процедуру, аналогичную процедуре Pr, которая вычисляла бы периметр и площадь квадрата со стороной r и а также объем куба с тем же самым ребром r.
(2 балла)
- 32 -
Тема имеет исключительно важное значение
В практике программирования часто встречаются задачи, в которых требуется применение регулярных, пронумерованных данных: таблицы, результаты наблюдений, проекции векторов, числовые матрицы, каталоги библиотек и т.д. Для работы с такими данными практически во всех языках программирования существует понятие массива.
Массив – это регулярная структура данных, которая состоит из пронумерованных компонент одного и того же типа. Этот тип мы будем называть базовым типом.
Массивы могут быть одномерными:
и многомерными (например, двумерными) :
С точки зрения машинной реализации, все массивы – одномерные, разница лишь в том, как пронумерованы элементы массива. Описание одномерного массива, если считать его элементы целыми числами выглядит следующим образом:
A : array [1..8] of integer;
здесь array – ключевое слово, которое и обозначает собственно массив, в квадратных скобках указан диапазон первого и единственного индекса.
В Pascal’е в качестве диапазона индекса может выступать любой отрезок перечислимого типа, например ‘A’..’H’, либо 0..7. Однако на практике чаще всего удобнее в качестве индексов использовать отрезок целого типа, причем нижний (меньший) индекс разумно выбирать единицей или нулем.
Одной из самых неприятных ошибок программирования – является ошибка обращения к несуществующему элементу массива, или как говорят, ошибка выхода индекса за допустимый диапазон. Поэтому предыдущее определение массива A лучше переписать так:
Const N = 8;
Var A : array [1..N] of integer;
и в дальнейшем в программе при работе с массивом использовать не конкретные числа, а константы, которые определяют диапазон индексов, кроме того, программу можно будет легко модифицировать для работы с массивом другой размерности, так как необходимо будет изменить всего лишь одну строчку!
- 33 -
Иногда формальность описания следует развить, выделив описание типа отдельно, это будет абсолютно необходимо, если вы собираетесь использовать в процедурах и функциях параметры-массивы.
Const N = 8;
Type TA = array [1..N] of integer;
Var A : TA;
Дополнительные удобства этого подхода заключаются в том, что массивы, описанные в разных местах как массивы типа TA, будут являться совместимыми по типу, а в случае описания массивов A и B одинаковым способом, но без объявления типамассива, они будут считаться несовместимыми. Например,
Const N = 8;
Type TA = array [1..N] of integer;
Var A : TA;
Var B : TA;
здесь A и B – массивы одного и того же типа. А здесь:
Const N = 8;
Var A : array [1..N] of integer;
Var B : array [1..N] of integer;
здесь A и B – массивы будут считаться разных типов. Хотя следующее описание определяет массивы одинаковых типов:
Const N = 8;
Var A,B : array [1..N] of integer;
В качестве базового типа допустим абсолютно любой тип, в том числе и массив, т.е. допустим массив массивов:
Const M = 5; N = 8;
Var A : array [1..M] of array [1..N] of integer;
Подобная ситуация встречается довольно часто, поэтому для нее существует разумное сокращение:
Const M = 5;
N = 8;
Var A : array [1..M,1..N] of integer;
Следует учесть, что многомерные массивы, даже при небольших диапазонах индексов имеют тенденцию занимать много памяти.
Основные приемы работы с массивами
Рассмотрим выполнение элементарных манипуляций с массивами. Самая простая задача – заполнение всех элементов одним и тем же значением:
{Инициализация массива}
for i:=1 to N do A[i]:=0;
Обратите внимание, как осуществляется доступ к элементам массива – после имени массива в квадратных скобках указывается индекс, который может быть произвольным выражением, лишь бы его значение не выходило за указанный при описании диапазон.
Подобная конструкция допустима везде, где допустима простая переменная.
- 34 -
Цикл for – чрезвычайно удобная и полезная вещь при работе с массивами.
Оператор вида for i:=1 to N do – можно «переводить» как «выполнить для всех элементов массива».
Если два массива одного типа, то допустимо присваивание одного массива другому одним оператором:
B:=A;
Следующие два примера показывают, как осуществить ввод-вывод с небольшим сервисом:
{ввод массива}
for i:=1 to N do
begin
write('Ввeдите ',i,'-й элемент: ');
readln(A[i])
end;
Из этого примера видно, что массив вводится поэлементно, и как организовать нехитрый сервис. Вывод производится аналогично:
{вывод массива}
for i:=1 to N do
writeln ('A[ ',i,']=',A[i]);
Теперь рассмотрим самую первую нашу задачу на обработку массива – поиск максимального элемента. Поступим следующим образом: пусть максимальный элемент массива – первый, заведем для него специальную переменную; затем будем просматривать поочередно последующие элементы, и если окажется, что нам встретится элемент больший, чем уже определенное число, то заменим его на этот элемент массива.