- •Windows -приложение
- •Среда программирования
- •Встроенный отладчик
- •Использование графики
- •Графические данные и палитра
- •Сохранение проекта
- •Структура приложения
- •Структура модуля
- •Простые типы
- •Символьные типы
- •Логические типы
- •Тип перечень
- •Составной оператор
- •Оператор if
- •Оператор цикла for
- •Оператор цикла while
- •Оператор цикла repeat
- •Пример приложения 6
- •Пример приложения 7
- •Статические массивы
- •Динамические массивы
- •Оператор with
- •Идентичность типов
- •Совместимость типов
- •Преобразование типов
- •Операторы обработки исключительных ситуаций
- •Рекурсия
- •Процедура exit
- •Директивы подпрограммы
- •Класс как объектный тип
- •Наследование
- •Операции is и as
- •Типы ссылки на класс
- •Типизированные файлы
- •Файлы без типа
- •Пример приложения 17
- •Компонент tmainmenii
- •Двунаправленные списки
- •Потоки данных
- •Пример приложения 22
- •Интерфейс drag and drop
- •Пример приложения 24
- •С файлами
- •Пример приложения 26
- •Программные потоки
- •Приоритеты потоков
- •Класс tthread
- •Проблемы синхронизации потоков
Рекурсия
Допускается, что подпрограмма может вызывать саму себя. Эта возможность связана с тем, что при каждом новом обращении к подпрограмме, параметры, которые она использует, заносятся в стек. Причем, параметры из стека удаляются при выходе из подпрограммы. Таким образом, в стеке сохраняются все параметры от предыдущих вызовов. В ряде случаев рекурсивное оформление подпрограммы более компактное и эффективное. Но не следует забывать, что существует опасность переполнения стека. Классическим примером рекурсии является рекурсивная формула вычисления факториала
m=N(N-1)! (N-1)1 = (N-1)(N-2)! и т.д.
Напишем подпрограмму вычисления факториала по рекурсивной формуле.
Function Factorial(N: byte): Cardinal; Begin
If N in [0,1] then Result:=l
Else Factorial:=N*Factorial(N-l); End; .
При вычислении следует рассматривать прямой ход и обратный. В данном случае при прямом ходе в стек заносятся только данные. При обратном ходе происходят вычисления и удаляются параметры из стека.
ФОРМАЛЬНЫЕ И ФАКТИЧЕСКИЕ ПАРАМЕТРЫ
Формальные параметры задаются при объявлении подпрограммы, фактические параметры указываются при выполнении расчетов, т.е. при вызове подпрограммы. Фактические параметры должны быть идентичных типов с формальными. Их число должно быть равно числу формальных параметров, должен совпадать и порядок следования фактических параметров с порядком записи формальных. Механизм передачи данных через формальные параметры реализуется с использованием специальной области памяти -стека. По умолчанию размер стека установлен 16384 байта. Можно изменить объем стека в настройках среды Delphi.
ПАРАМЕТРЫ-ЗНАЧЕНИЯ
В этом случае для передаваемого фактического параметра создается копия в стеке. Синтаксис записи, например, таков: Function FF(a,b:Real; ...) :...; (пример приведенной выше подпрограммы содержит этот тип параметров). На месте параметра-значения при вызове подпрограммы может стоять выражение, совместимое по присваиванию с формальным параметром.
102
Внутри подпрограммы значение такого параметра измениться не может. Входные параметры можно задавать как параметры-значения. Передавать в подпрограмму массивы в виде параметров-значений нецелесообразно, так как расходуется лишняя память - в стеке создается дополнительная копия массива.
ПАРАМЕТРЫ-ПЕРЕМЕННЫЕ
При использовании в подпрограммах параметров-переменных в стеке выделяются ячейки для размещения адресов фактических параметров. В отличие от параметров-значений, внутри подпрограммы значения параметров-переменных могут изменяться. Так как фактические параметры в этом случае передаются по адресу, любое изменение параметра-переменной внутри подпрограммы, таким образом, фиксируется в фактическом параметре. Параметр-переменную записывают, используя ключевое слово var, например Procedure PP(var c:integer; ...); (пример процедуры выше содержит этот тип параметра). Выходные параметры задаются как параметры-переменные.
ПАРАМЕТРЫ-КОНСТАНТЫ
Параметры-константы синтаксически введены для того, чтобы ключевое слово var сохранить за выходным параметром и в то же время чтобы входной параметр мог передаваться по адресу. Синтаксис записи этих параметров таков: Procedure PP(const a:real; ...); (пример процедуры, приведенной выше, содержит этот тип параметров). В данном случае простые переменные передаются как копии, а, например, массивы и строки - по адресу. Компилятор сам определяет, что передавать по адресу, а что как копию. Изменить параметры-константы внутри подпрограммы нельзя. Таким образом, входные параметры могут передаваться в подпрограмму как параметры-константы. Вместо параметров-констант можно подставлять выражения, как и для параметров-значений.
ПАРАМЕТРЫ БЕЗ ТИПА
Существуют параметры-переменные и параметры-константы без указания их типа. Передаются такие параметры по адресу. При использовании этих параметров внутри подпрограммы необходимо определить их тип и воспользоваться, например, преобразованием типов. Рассмотрим следующий пример: пусть требуется найти максимальный элемент для заданного одномерного массива. Напишем функцию поиска максимального элемента.
Function MMax(var a): Integer; Type Vect = array of integer;
103
Var i : byte; Begin
Result := Vect(a)[0];
For i := 1 to High<Vect(a)) do
If Result < Vect(a) [i] then Result := Vect(a) [i]; End;.
В качестве фактического параметра в данном случае можно использовать любой одномерный динамический массив целых чисел, размерность этого массива может быть любая. Пусть требуется найти с помощью этой функции максимальный элемент для вектора В, состоящего из 20 элементов. Сначала объявим этот вектор и переменную Y, в которую запишем результат: Var в: array of integer; Y: integer;. Далее надо определить массив, предварительно выделив для него память: setLength(B,20);. Теперь запишем вызов функции Y:=Mmax(B) ,-.
МАССИВЫ ОТКРЫТОГО ТИПА
В подпрограммах нельзя объявлять формальный параметр как статический массив в виде array [...] of ..., так как он не будет идентичен ни одному фактическому параметру. Если все же необходимо обмениваться с подпрограммой данными в виде статических массивов, то предварительно их надо типизировать, например, Type vekt = array [1..20] of real; ...procedure sum (const V:Vekt; ...).
Чаще всего при вычислениях с векторами или матрицами формальные параметры в подпрограммах описывают как открытые массивы, используя тот же синтаксис и все правила, которые применяются при работе с динамическими массивами. Перепишем предыдущую функцию, для того чтобы можно было передавать одномерный массив любой размерности и не использовать преобразование типов внутри подпрограммы.
Function Mmax(const Mas: array of Integer): Integer;
Var I : Byte; Begin
Result := Mas[0];
For i := 1 to High(Mas) do
If Result < Mas[i] then Result := Mas[i]; End;.
Если формальный параметр представляет собой открытый массив, то в качестве фактического параметра можно использовать конструктор массива. Конструктор массива разрешается применять, если открытый массив задан в виде параметра-константы, как в предыдущей функции Мшах. Конструктор открытого массива по синтаксису записи совпадает с конструктором множества. Пусть заданы три значения: а, 15, b + с, где а,Ь,с- переменные.
104
Найти среди них максимум с помощью подпрограммы Mmax и результат записать в Y-y := ММах([а, 15, Ь + с]);.
Если необходим обмен данными с помощью массивов вариантного типа, то используется формальный параметр типа Array of const (открытый массив вариантного типа).
ПАРАМЕТРЫ ПО УМОЛЧАНИЮ
Часто при вызове подпрограммы в нее нужно передавать параметры, имеющие некоторое заданное значение. Например, получить распределение случайных чисел, зависящее от многих параметров, но при одном заданном k = 5 или к = 9, где к - некоторая характеристика, остальные параметры изменяются одинаково. Заменить такие параметры, как к, на константы нельзя - все же они иногда меняются. Эта проблема решается введением параметров по умолчанию. Например, запишем функцию для вычисления распределения Гаусса:
Здесь х - случайная величина, заданная в диапазоне- от а до b с шагом h; m=(a+b)/2; a - параметр, по умолчанию равный 1 (но иногда требуется задать значение, например 0,5 или 2).
Function Gaussa(x, m: real; sigma: real=1.0): real;
Begin
Result:=exp{-sqr(x-m)/(2*sqr(sigma)))/
(sqrt(2*:c) *sigma) ;
End;
При выполнении расчетов можно записать так: Y: = Gaussa(x, (a+b)/2) опуская параметр sigma, или так: Y: = Gaussa(x,(a+b)/2,2.0);.
Очень важно отметить следующее. Параметров по умолчанию может быть несколько. Но все они должны быть сосредоточены в конце списка параметров. Объяснение этому очень простое. Допустим, подпрограмма имеет 4 параметра. Из них первые два - параметры по умолчанию. В этом случае, если указаны при вызове подпрограммы 3 параметра, то как определить, что это первый, третий и четвертый или второй, третий и четвертый. Поэтому параметры можно опускать начиная с конца, например для функции
Function MyFF(x:byte= 1; y:byte= 1; z:byte= 1):byte; можно записать Так: A:=MyFF(2,2,2) ;, A:=MyFF<2,2) ;, A:=MyFF(2);, A:=MyFF;, a TSK Записывать нельзя: A:=MyFF(, 2, 2); A:=MyFF(2, , 2);.
Параметром по умолчанию может быть только константа или константное выражение, т.е. то, что можно определить на этапе компиляции.
105