
Лекция 3
<Раздел объявления типов > :: =
type // Признак начала раздела объявления типов
<Имя Типа 1> = <Спецификация Типа 1> ;
<Имя Типа 2> = <Спецификация Типа 2> ;
. . .
Пример.
type
MyInt = integer;
MyDouble = double;
<Раздел объявления типизированных констант> :: =
const // Признак начала раздела объявления констант
<Имя константы 1> : <Тип 1> = < Константное выражение 1> ;
<Имя константы 2> : <Тип 2> = < Константное выражение 2> ;
. . .
Пример:
const
n: longint = 2000000000;
EulerGamma: double = 0.5772156649015329;
pi_half: double = pi / 2.0; pi_quarter: double = pi_half / 2.0;
Замечание. В Turbo Pascal 7.0 «типизированная константа» на деле константой не является: в тексте программы эту «константу» можно изменять. «Типизированная константа» – это, в действительности, инициализированная переменная.
Замечание. Типизированная константа не может участвовать в константном выражении.
Замечание. В Delphi типизированные константы, в отличие от констант без типа, могут принимать значения массивов, записей, процедур, указателей.
Если действует ключ компиляции {$J-} (явно или по умолчанию), значения, принятые типизированными константами при объявлении, не могут быть изменены. Напротив, ключ {$J+} дает типизированным константам возможность изменяться по ходу исполнения программы.
Замечание. В языке «C++» инициализированные переменные объявляются так:
<Тип 1>
<Имя 1> = <Константное выражение 1>,
<Имя 2> = <Константное выражение 2>,
. . .
<Имя N> = <Константное выражение N>;
<Тип 2>
<Имя N+1> = <Константное выражение N+1>,
. . .
Примеры.
int I = 2, J = –5, K = 888;
double x = 1.0, y = –2.2, z = 0.123;
char c = ‘Q’;
Цикл с постусловием
repeat <Операторы> until <Л.В.>
<Операторы> являются телом цикла.
Тело цикла выполняется по меньшей мере один раз, а затем, возможно, многократно, пока < Л.В.> есть ложь.
Если < Л.В.> есть истина при первой же оценке, то тело цикла выполняется один раз.
Если < Л.В.> есть ложь при каждой оценке, то тело цикла выполняется неограниченно много раз.
В случае, если тело цикла содержит несколько операторов, нет необходимости использовать операторные скобки. Слово repeat заменяет собой begin, тогда как слово until заменяет собой end.
Замечание. В языке «C++» родственная конструкция имеет вид:
do <Оператор> while (<Л.В.>)
«Полностью» аналогичная конструкция имеет вид:
do <Оператор> while (! <Л.В.>)
Знак логической инверсии «!» необходим, если истинность <Л.В.> должна приводить к прекращению цикла.
Замечание по теме «циклы»
Инструкция break применяется для досрочного прекращения цикла. Равноценна оператору “goto Metka1”, для которого “Metka1:” расположена сразу после оператора цикла.
Инструкция continue применяется для досрочного перехода на очередную проверку условия продолжения цикла.
Равноценна оператору “goto Metka2”, для которого “Metka2:” расположена сразу после последнего из операторов, составляющих тело цикла.
Инструкции break и continue в Паскале заимствованы из языка «C++».
Процедуры
<Объявление процедуры> :: =
procedure <Имя процедуры>[(<Список формальных параметров)];
<Разделы объявления локальных типов, констант, переменных>
<Разделы объявления локальных процедур и функций>
begin |
} Раздел исполнения (тело) процедуры |
<Операторы> |
|
end; |
<Список формальных параметров> :: =
<Элемент списка 1>; <Элемент списка 2>; . . .
<Элемент списка> :: =
<Список имён параметров-значений>: <Тип>
или
var <Список имён параметров-переменных>: <Тип>
или
const <Список имён параметров-констант>: <Тип>
<Обращение к процедуре> :: =
<Имя процедуры>[(<Список фактических параметров>)]
Замечание. Фактические параметры должны быть совместимы с формальными по типам.
Параметр-значение сам процедуре не передаётся. Передаётся лишь его «численная» (или иная, согласно типу параметра) копия, под которую выделяется дополнительное место в оперативной памяти. Это важно иметь в виду, особенно, если параметр занимает много места в памяти.
Переменная, реализующая параметр-значение, может быть, при необходимости, использована, как локальная переменная.
По окончании работы процедуры эта переменная становится недоступной. Новое значение, приданное ей в теле процедуры, недоступно в том месте, из которого процедура вызвана.
Параметр-переменная именно сам передаётся процедуре. Изменения, произошедшие с таким параметром, сохраняются и по окончании работы процедуры.
Параметр-константа также сам передаётся процедуре. Изменения такого параметра в теле процедуры запрещены.
Пример.
program Example2;
type
MyInt = integer ;
var
I : MyInt ;
J: integer ;
procedure P2(var M: integer);
begin
. . .
end;
begin
P2(J) ; // Нормально
P2(I) ; // Ошибка. Несоответствие типов
end.
Пример.
program Example3;
var
I, J, K : integer ;
procedure P3(L : integer ; var M : integer ; const N : integer);
begin
Inc(L) ; // Бесполезно
Inc(M) ; // Полезно
(* Inc(N) ; *) // Ошибка
end;
begin
I := 1; J := 1; K := 1;
P3(I, J, K) ;
wri teln(‘I=’, I) ; // I = 1, переменная не изменилась
wri teln(‘J=’, J) ; // J = 2, переменная изменилась
end.
Замечание. В языке «C++» процедур нет. Роль процедур исполняют функции, возвращающие значение void (пусто).
<Объявление функции void> :: =
void <Имя функции>([<Список формальных параметров>])
{ |
} Раздел исполнения (тело) функции |
<Операторы> |
|
} |
<Список формальных параметров> :: =
<Элемент списка 1>; <Элемент списка 2>; . . .
<Элемент списка> :: =
<Тип> <Имя параметра-значения>
или
const <Тип> <Имя параметра-значения>
Пример.
#include <vcl.h>
#include <stdio.h>
#include <conio.h>
#pragma hdrstop
int
I, J, K, Q;
void P3(int L; int *M; const int N; const int *P)
{
L++ ; // Бесполезно
*M++ ; // Полезно
// N++ ; // Ошибка
// *P++ ; // Ошибка
// P++ ; // Ошибка
}
int main(int argc, char* argv[])
{
I = 1; J = 1; K = 1; Q = 1;
P3(I, &J, K, &Q) ;
printf(“I=%d”, I) ; // I = 1, переменная не изменилась
printf (“J=%d”, J) ; // J = 2, переменная изменилась
{
Функции
<Объявление функции> :: =
function <Имя функции>(<Список формальных параметров>) :
<Тип возвращаемого значения>;
<Разделы объявления локальных типов, констант, переменных>
<Разделы объявления локальных процедур и функций>
begin |
} Раздел исполнения функции |
<Операторы> |
|
end; |
Среди <Операторов> должен быть хотя бы один «Оператор» вида
<Имя функции> := <Выражение> ;
или
result := <Выражение> ;
Пример.
program Example4;
var
x, y, Eps : Double ;
function BesselI0(x, Eps : Double) : Double ;
var
S, A, B, R: Double ;
begin
. . .
BesselI0 := S ;
end;
begin
writeln(‘x=? ’) ; readln(x);
writeln(‘Eps=? ’) ; readln(Eps);
y := BesselI0(x, Eps) ; writeln(‘y=’, y) ;
end.
,
Условия
прекращения цикла суммирования:
и
S0 = 0 |
A0 = 1 |
|
S1 = S0 + A1 |
A1 = A0*B1 |
B1 = (x/2)2/12 |
S2 = S1 + A2 |
A2 = A1*B2 |
B2 = (x/2)2/22 |
. . . |
. . . |
. . . |
Si = Si-1 + Ai |
Ai = Ai-1* Bi |
Bi = (x/2)2/i2 |
Текст программы на языке Free Pascal, TP7:
program BesselI0 ; // Необязательная строка
var
x,y: Double;
function BesselI0(x, Eps : Double): Double;
var
I, N: integer;
S, A, B, R, x2: Double;
begin
S := 0 ;
x2 := sqr(x/2) ;
A := x2 ;
N := 0 ;
B := x2 / (N + 2) / (N + 2) ;
repeat
inc(N);
A := A * B ;
B := x2 / (N + 2 ) / (N + 2) ;
R := A / (1 - B) ;
until ( B < 1) and ( R < Eps ) ;
S := 1;
A := 1;
S0 = 0 |
A0 = 1 |
|
S1 = S0 + A1 |
A1 = A0*B1 |
B1 = (x/2)2/12 |
S2 = S1 + A2 |
A2 = A1*B2 |
B2 = (x/2)2/22 |
. . . |
. . . |
. . . |
Si = Si-1 + Ai |
Ai = Ai-1* Bi |
Bi = (x/2)2/i2 |
for I := 1 to N do
begin
B := x2 / I / I;
A := A * B;
S := S + A;
end;
BesselI0 := S ;
end ;
begin
writeln(‘Введите x’) ; readln(x) ;
writeln(‘Введите Eps’) ; readln(Eps) ;
if (Eps <= 0) or (Eps >= 1) then exit ;
writeln(‘f=’, BesselI(x, Eps));
readln;
end.
Тип «Перечисляемый»
<Перечисляемый тип> : : =
(<Список имён значений>)
Первому из элементов <Списка имён значений> придаётся внутренний (недоступный пользователю) номер 0, второму – номер 1, и т.д.
Переменные типа «Перечисляемый»
Примеры
var
v1: (LeftDyrecton, RightDyrecton, BackDyrecton);
type
MyType2=(Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday);
MyType4=(MyTrue, MyFalse);
var
MyVar2: MyType2;
MyVar3: boolean;
MyVar4: MyType4;
begin
for MyVar2 :=Monday to Friday do writeln(MyVar2); // Ошибка
for MyVar4 :=MyFalse to MyTrue do writeln(MyVar4); // Ошибка
for MyVar3 := False to True do writeln(MyVar3); // Выход: True False
end.
Замечание. boolean ≠ (False, True). Вообще говоря.
Замечание. Тип «Перечисляемый – порядковый тип.
Диапазон
<Диапазон> : : =
<Целое число 1> . . <Целое число 2>
Естественное требование:
<Целое число 1> не более, чем <Целое число 2>
Примеры.
1 . . 5
First . . Third
// Если выше по тексту было что-то наподобие:
// const First = 0; Third = 2;
Тип «Диапазон»
type <Имя типа> = <Диапазон> ;
Пример.
type MyType01 = –3 . . 72 ;
Переменные типа «Диапазон»
Примеры:
var
v1: 22 . . 44 ;
v2: MyType01 ;
const
v3: MyType01 = 6 ;
const
MyConst11 = 1; MyConst12 = 7;
type
MyType02 = MyConst11 .. MyConst12;
var
MyVar02: MyType02;
Замечание. Тип–Диапазон – порядковый тип.
Массивы
Все типы переменных, изученные до сих пор – скалярные (простые) типы.
Массив – вектор, матрица, ...
Массив – упорядоченная совокупность данных одного типа.
Массив – переменная с индексом (со списком индексов).
<Объявление одномерного массива> : : =
<Имя переменной> : array[<Диапазон>] of <Тип элемента> ;
<Объявление нескольких многомерных массивов> : : =
<Список имён > : array[<Список диапазонов>] of <Тип элемента> ;
или
<Список имён > : <Тип-массив> ;
<Тип-массив> : : =
array[<Список диапазонов>] of <Тип элемента > ;
<Обращение к элементу массива> : : =
<имя массива> [ <Список значений индексов> ]
Пример
const
MyConst21 = 1; MyConst22 = 8;
type
MyRange1 = 1 . . 7;
MyRange2 = MyConst21 . . MyConst22;
var
A: array[1 . . 4] of integer;
A1, A2, A3: array[1 . . 4, -1 . . 7] of double;
A4: array[MyRange1] of double;
A5: array[MyRange1, MyRange2] of double;
begin
A[3] := 99;
A1[2, 6] := 5.3;
A2[1][7] := 4.1e-10;
A3[5, 0] := 2;
end.
Пример. Заполнить матрицу числами, составляющими треугольник Паскаля.
,
.
,
.
const
n=16;
type
MyArrayType = array[0 . . n , 0 . . n] of integer;
. . .
procedure PT(var mG: MyArrayType);
// procedure PT(var mG: array[0 . . n , 0 . . n] of integer);
var
m, k: integer;
begin
for m := 0 to n do for k := 0 to n do mG[m, k] := 0;
mG[0, 0] := 1;
for m := 1 to n do
begin
mG[m, 0] := 1; mG[m, m] := 1;
for k := 1 to m-1 do mG[m, k] := mG[m-1, k] + mG[m-1, k-1];
end;
end;
. . .