А. С. Панкратов лекции по информатике для студентов инженерных специальностей Структура программы на Паскале Вклассическом варианте языка Паскаль программа
Вид материала | Лекции |
- Структура программы языка Турбо Паскаль Программа на языке Турбо Паскаль имеет вид, 792.5kb.
- Структура программы на языке Турбо Паскаль Программа, написанная на языке Турбо Паскаль,, 229.09kb.
- В. А. Атрощенко и др. Лекции по общей информатике. Краснодар, 2010, Кубгту, 33.55kb.
- Структура программы на Паскале Система программирования Турбо Паскаль, 145.34kb.
- С. В. Элективный курс «Программируем на Паскале» общие вопросы самылкина Н. Н. Программа, 503.53kb.
- Циклические программы. Структурированный тип данных. Структура сложной программы, 860.21kb.
- Программа Для студентов всех специальностей Лекции, 180.91kb.
- Рабочая программа и индивидуальные контрольные задания для студентов специальности, 920.99kb.
- Язык Паскаль позволяет составлять программы для решения математических задач, обработки, 50.57kb.
- Программа по курсу "Теория и методика обучения информатике" для студентов, 27.95kb.
А. С. Панкратов
ЛЕКЦИИ ПО ИНФОРМАТИКЕ
для студентов инженерных специальностей
1. Структура программы на Паскале
В классическом варианте языка Паскаль программа имеет следующую структуру:
Заголовок;
Блок описаний;
Блок операторов.
Заголовок имеет следующий вид:
program <имя программы>;
Имя программы должно начинаться с буквы (латинской) и содержать до 8 символов (латинские буквы, цифры, символ подчеркивания).
Заголовок заканчивается точкой с запятой. В языке Паскаль этот символ есть универсальный разделитель, отделяющий друг от друга, в частности, разделы програмы, разделы описаний, операторы.
В блоке описаний приводятся описания всех программных объектов, участвующих в данной программе. Такими объектами могут быть:
- метки (описание начинается со служебного слова label);
- константы (описание начинается со служебного слова const);
- нестнадартные типы (описание начинается со служебного слова type);
- переменные (описание начинается со служебного слова var);
- функции и процедуры (описание начинается со служебных слов function и procedure);
Блок операторов начинается со служебного слова begin и содержит операторы программы, разделенные точкой с запятой. Заканчивается блок операторов служебным словом end с точкой.
2. Основные типы данных
Каждый тип даных определяет множество допустимых значений. Некоторые типы в языке присутствуют изначально:
Тип integer. Числовые целочисленные значения в диапазоне от –32768 до 32767.
Тип real. Вещественные (действительные) числа в диапазоне от до .
Тип char. Символы (буквы латинские и русские, прописные и строчные, цифры, значки), которые имеются на клавишах клавиатуры.
Тип boolean. Логический тип. Только два возможных значения: true (истина) и false (ложь).
В языке Паскаль требуется, чтобы каждая величина была приписана к некоторому типу. Типы констант распознаются по их написанию (число без десятичной точки – целый тип, число с десятичной точкой – вещественный тип, символ, взятый в апострофы – символьный тип). Типы переменных указываются при их описании. Например:
var i,j:integer;x,y:real;
(i, j – целые, x, y – вещественные числа).
3. Оператор присваивания. Арифметические и логические выражения.
Оператор присваивания (знак :=) записывается следующим образом:
<имя переменной>:=<значение>
Слева от знака := стоит одиночная переменная, справа может стоять выражение соответствующего типа.
Выражение представляет собой величины, связанные операциями и функциями.
Основные операции языка Паскаль:
Операция | Тип операндов | Тип результата |
+, –, * | integer | integer |
+, –, * | real | real |
/ | integer, real | real |
div, mod | integer | integer |
and, or, not | boolean | boolean |
>, >=, <, <=, =, <> | integer, real, char, boolean | boolean |
Операции различаются по своему приоритету. Операции более высокого приоритета исполняются раньше операций низшего приоритета. Имеются четыре группы операций различного приоритета (от высшего к низшему):
1. not;
2. *, /, div, mod, and;
3. +, –, or;
4. >, >=, <, <=, =, <>.
При необходимости изменения порядка исполнения операций, принятого в соответствии с приоритетом, используются круглые скобки. Выражения, написанные в скобках, исполняются вне очереди.
Кроме операций на языке Паскаль имеются еще стандартные (встроенные) функции:
Функция | Тип аргумента | Тип результата | Описание |
abs(x) | integer | integer | |
abs(x) | real | real | |
sqr(x) | integer | integer | |
sqr(x) | real | real | |
sqrt(x) | real | real | |
sin(x) | real | real | sin x |
cos(x) | real | real | cos x |
arctan(x) | real | real | arctg x |
exp(x) | real | real | |
ln(x) | real | real | ln x |
odd(x) | integer | boolean | нечетность |
round(x) | real | integer | округление до ближайшего целого |
trunc(x) | real | integer | округление путем отбрасывания дробной части |
ord(a) | любой дискретно-упорядоченный | integer | порядковый номер |
chr(n) | integer | char | восстанавливает символ по порядковому номеру |
succ(a) | любой дискретно-упорядоченный | он же | следующий по порядку |
pred(a) | любой дискретно-упорядоченный | он же | предшествующий по порядку |
4. Условные операторы.
Условным оператором называется оператор, который выполняет то или иное действие в зависимости от некоторого условия.
Общий вид условного оператора:
а) полный вид:
if <условие > then <оп.1> else <оп.2>;
б) усечённый вид: if <условие> then <оп.1>;
где <условие> - некоторое выражение логического типа,
<оп.1> и <оп.2> - некоторые операторы языка Паскаль.
Действие условного оператора:
а) Полный вид: сначала вычисляется выражение <условие>. Если результат есть истина (true), то выполняется <оп.1>, если результат есть ложь (false), то выполняется <оп.2>.
Блок-схема:
да
нет
…
…
б) Усечённый вид: вычисляется <условие>. Если результат есть истина, то выполняется <оп.1>. Если результат есть ложь, то никакого действия не происходит .
Блок схема:
…
да
нет
…
Замечание 1. В качестве <оп. 1> и <оп. 2> по синтаксису языка Паскаль может присутствовать только один оператор. Если же при выполнении (или невыполнении) заданного условия надо выполнить сразу несколько операторов, то они должны быть объединены в один составной оператор (блок операторов) посредством операторных скобок begin и end:
begin
<последовательность операторов,
отделенных друг от друга точкой с запятой>
end;
З
амечание 2: Операторы <оп.1> и <оп.2> сами могут включать в себя условные операторы. В этом случае любая встретившаяся часть else соответствует ближайшей к ней слева части then.
П
ример. Дана область D (см. рисунок).
Даны два вещественных числа x и y, рассматриваемые как координаты точки на плоскости. Вычислить величины u и v по следующему праввилу:u=1, v=0, если точка (x,y) принадлежит D;u=0, v=1, если точка (x,y) не принадлежит D.
Р
ешение. Основное в данной задаче – правильно записать условие принадлежности точки области D. Разобьём область D на две части D1 и D2, то есть D=D1D2.
…
Тогда условие “(x,y) принадлежит D” можно записать как “(x,y) принадлежит D1” либо “(x,y) принадлежит D2”, где “(x,y) принадлежит D1” означает что:
1) (x,y) лежит внутри окружности с центром в начале коордиат радиусом 1;
2) (x,y) лежит левее оси Y;
3) (x,y) лежит выше оси X.
Э
то эквивалентно системе неравенств:
которая на языке Паскаль записывается так:
(x*x+y*y<=1) and (x<=0) and (y>=0).
Аналогично, условие “(x,y) принадлежит D2” означает, что:
1) (x,y) лежит ниже гипотенузы прямоугольного треугольника D2;
2) (x,y) лежит правее оси Y;
3) (x,y) лежит выше оси X,
ч
то эквивалентно системе неравенств
которая на языке Паскаль записывается так:
(y<=1-x) and (x>=0) and (y>=0)
Окончательно, условие “(x,y) принадлежит D” записывается так:
((x*x+y*y<=1)and(x<=0)and(y>=0))or
((y<=1-x)and(x>=0)and(y>=0))
Программа:
program pr1;
var x,y:real;
u,v:integer;
begin
writeln(введите x,y);
read(x,y);
if ((x*x+y*y<=1) and (x<=0) and (y>=0)) or
((y<=1-x) and (x>=0) and (y>=0)) then
begin
u:=1;
v:=0
end else
begin
u:=0;
v:=1
end;
writeln(u=,u,_v=,v)
end.
5. Циклы
Операторами цикла называются операторы, многократно повторяющие одни и те же действия.
На языке Паскаль существует три вида операторов цикла.
1. Оператор цикла с параметром (цикл FOR)
Общий вид:
for <пар.>:=<n1> to <n2> do <оп.> ;
где:
<пар.> – параметр цикла, переменная дискретно-упорядоченного типа, как правило типа integer,
<n1> – выражение того же типа, начальное значение параметра, присваиваемое ему на входе в цикл,
<n2> – выражение того же типа, конечное значение параметра,
<оп.> – оператор, выполнение которого повторяется до тех пор, пока параметр цикла, увеличиваясь после каждого шага на единицу, не превысит <n2>.
Иными словами, цикл for действует следующим образом: вначале вычисляется параметр <n1> и осуществляется присваивание <пар.>:=<n1>. После этого циклически повторяется (для параметра целого типа):
1) проверка условия <пар.>+1, если условие не выполняется (т.е. <пар.>=+1) , то цикл завершается;
2) выполнение оператора <оп.>;
3) увеличение переменной <пар.> на единицу.
Замечание 1: Переменная <пар.>, а также выражения <n1> и <n2> не могут быть типа real, так как он не является дискретно-упорядоченным.
Замечание 2: В качестве <оп.> может присутствовать только один оператор. В случае, если повторяться должны сразу несколько операторов, то их надо сформировать в блок с помощью операторных скобок begin и end.
Блок-схема: цикла FOR:
…
выход из цикла
да
нет
…
Другая форма оператора FOR:
for <пар.>:=<n2> downto <n1> do <оп.> ;
В этом случае оператор <оп.> повторяется при уменьшении параметра цикла на единицу. Цикл завершается при достижении условия <пар.>=<n1>–1.
Блок-схема:
…
нет
да
выход из цикла
…
2. Оператор цикла с предусловием (цикл WHILE)
Общий вид:
while <условие> do <оп.> end;
где:
<условие> – выражение логического типа,
<оп.> – оператор.
Действие. Циклически повторяется:
1) проверка выражения <условие>. Если результат есть false (т.е. <условие> ложно), то цикл завершается;
2) в случае, если <условие> истинно, выполняется оператор <оп.>.
Б
…
лок-схема:
нет
да
выход из цикла
…
Замечание: Как и в цикле FOR, в качестве <оп.> может присутствовать только один оператора. Если операторов, которые должны повторяться, больше одного, то они должны быть сформированы в блок с помощью операторных скобок begin и end.
3. Оператор цикла с постусловием (цикл REPEAT)
Общий вид:
repeat
<оп.1>;
<оп.2>;
…………
<оп.N>;
until <условие>;
где:
<оп.1>, <оп.2> ,…, <оп.N> – операторы,
<условие> - выражение логического типа.
Действие. Последовательность операторов <оп.1>, <оп.2> ,…, <оп.N> выполняется хотя бы один раз, после чего проверяется <условие>. Если результат есть true, то цикл завершается. В противном случае опять выполняется последовательность операторов , <оп.2> ,…, <оп.N> , затем снова проверяется условие и так далее.
Блок-схема:
…
…
нет
да
выход из цикла
Замечание 1. Конструкция repeat … until позволяет повторять сразу несколько операторов, поэтому здесь не требуется (как в случае FOR и WHILE) формировать операторы в блок.
Замечание 2. <условие> в цикле WHILE и <условие> в цикле REPEAT имеют противоположный смысл: в цикле WHILE <условие> есть условие продолжения цикла, а в цикле REPEAT <условие> есть условие окончания цикла.
Пример 1. Дано целое n. Вычислить сумму
Решение. Для обозначения суммы вводится переменная s, которой изначально присваивается значение 0. Затем организуется цикл, на каждом шаге которого к s прибавляется очередное слагаемое. Поскольку известны границы изменения k (от 0 до n), то в качестве оператора цикла удобнее всего взять цикл FOR с параметром k и границами 1 и n.
Программа:
program pr2;
var k,n:integer; s:real;
begin
writeln(введите n);
readln(n);
s:=0;
for k:=1 to n do
s:=s+k/(1+k*k*k);
writeln(s=,s)
end.
Пример 2. Сумма тех же слагаемых, что и в примере 1, только вместо n даётся вещественное число (степень точности). Требуется суммировать до тех пор, пока очередное слагаемое не станет меньше .
Решение. В этом случае число слагаемых заранее не известно, зато известно условие, при котором следует закончить суммирование. Поэтому удобнее использовать цикл с выходом по условию, например REPEAT. Для обозначения очередного слагаемого удобно ввести переменную а.
Программа:
program pr3;
var k,eps,s,a:real;
begin
writeln(введите eps);
read(eps);
s:=0;
k:=1;
a:=0.5;
repeat
s:=s+a;
k:=k+1;
a:=k/(1+k*k*k)
until abs(a)
writeln(s=,s)
end.
Пример3. Даны n, m. Вычислить сумму
Решение. Считается сумма по двум параметрам, следовательно используется конструкция «цикл в цикле». Внутренний цикл считает сумму по j при фиксированном i, внешний – сумму по i.
Программа:
program pr4;
var i,j,m,n:integer;
s:real;
begin
writeln(введите m,n);
read(m,n);
s:=0;
for i:=2 to m do
for j:=1 to n do s:=s+1/(i*i+j*j*j);
writeln(s=,s)
end.
Пример 4. Даны х,n. Вычислить сумму
Решение: Здесь слагаемое имеет более сложную структуру – оно содержит факториал k!=1*2*3*…*k, вычисление которого есть само по себе цикл, степень , операции для вычисления которой в данной версии паскаля нет, и «мигалку»
Если решать эту задачу “в лоб”, то придётся делать цикл в цикле для вычисления факториала, степень вычислять как exp(k*ln(x)), при этом он не будет работать для х отрицательных, так как логарифмов отрицательных чисел не существует, и отдельно вычислять величину (–1)k. Это существенно усложняет как саму программу, так и работу компьютера. Поэтому для решения таких задач следует использовать технику рекуррентных соотношений.
Рекуррентным соотношением называется формула, позволяющая выражать каждый член последовательности через предыдущий (или несколько предыдущих).
Для выведения рекуррентного соотношения требуется проделать некоторую предварительную работу перед написанием программы. В нашем примере это будет выглядеть так.
Обозначим k-й член суммы через , то есть .
Требуется вывести соотношение, позволяющее выразить через .
Для этого выпишем (подставим в k+1 вместо k):
Разделим на :
Следовательно, .
Это и есть искомое рекуррентное соотношение.
Отдельно посчитаем первое , входящее в сумму, то есть :
=–х.
Теперь, зная , подставим его в правую часть рекуррентного соотношения, получим ; подставив в правую часть, получим и так далее.
В программе это реализуется следующим образом – в цикле одновременно с подсчетом s считается и следущее слагаемое ak.
program pr5;
var s,x,a:real;
k,n:integer;
begin
writeln(введите x,n);
readln(x,n);
s=0;
a:=-x;
for k:=1 to n do
begin
s:=s+a;
a:=-a*x/(k+1);
end;
writeln(s=,s)
end.
Данная техника позволяет избежать вычисления больших степеней и факториалов, они постепенно “накапливаются” в а от шага к шагу.
Пример 5. Сумма
В рассмотренном примере 4 мы получили рекуррентное соотношение за счёт свойства сокращаемости степеней и факториалов. Косинус таким свойством не обладает., поэтому, обозначив , придём к рекуррентному соотношению, в котором будет присутствовать отношение косинусов. Это не лучший вариант, поэтому предлагается за а обозначать только то, что что сможет сократиться при делении, а всё остальное добавлять в процессе вычисления суммы. В нашем случае положим как и прежде . Фрагмент программы, считающий s будет теперь выглядеть следующим образом:
s:=0;
a:=-x;
for k:=1 to n do
begin
s:=s+a*cos(k*x);
a:=-a*x/(k+1);
end;
6. Одномерные массивы
Одномерным массивом называется упорядоченная совокупность однотипных элементов (компонент массива), рассматриваемых как единое целое. Каждый элемент массива снабжается индексом (номером). Поэтому массив можно назвать совокупностью переменных с индексами. В качестве индекса может быть переменная или выражение дискретно-упорядоченного типа, как правило типа integer. Индекс не может быть типа real, так как этот тип не является дискретно-упорядоченным. Говоря более точно, множество индексов должно определяться заданием типа-диапазона, который указывается при описании массива в квадратных скобках за словом array (см. ниже). Количество элементов массива называется размером массива.
Описание массивов.
Описать какую-либо переменную как массив можно двумя способами.
1 способ. Определяется тип массива следующим образом:
type <имя типа>=array[<диапазон индексов>] of <тип компонент>;
<диапазон индексов> задается нижней и верхней границами изменения индекса массива.
Затем описывается переменная массива как принадлежащая типу <имя типа>:
var <имя переменной>: <имя типа>;
Например, массив a из 10 вещественных чисел (т.е. набор переменных с индексами a1, a2, … , a10 можно описать так:
type mass=array[1..10] of real;
var a:mass;
2 способ. Описать переменную как массив можно и непосредственно без предварительного описания типа:
var <имя переменной>:array[<диапазон индексов>] of <тип компонент>;
В нашем примере
var a:array[1..10] of real;
В этом случае тип массива будет безымянным.
Замечание. В нашем примере массива из 10 чисел можно было бы сделать следующие описания:
var a:array[0..9] of real;
или
var a:array[-4..5] of real;
Это бы по прежнему означало, что a есть массив из 10 вещественных чисел, только занумерованных соответственно от 0 до 9 либо от –4 до 5
Обращение к элементам массива.
При использовании какого-либо элемента массива в программе его индекс ставится в квадратные скобки сразу же за именем массива, например, i-й элемент массива a (ai) записывается как a[i].
Ввод массива.
В любом случае ввод (и вывод) массива осуществляется в цикле.
1. Единовременный ввод:
var a:array[1..10] of real;
k:integer;
. . . . . . . . . . . .
writeln(введите 10 чисел’);
for k:=1 to 10 do read(a[k]);
2. Поэлементный ввод:
var a:array[1..10] of real;
k:integer;
. . . . . . . . . . . .
for k:=1 to 10 do
begin
writeln(введите a[’,k,’]’);
read(a[k]);
end;
Массивы с неизвестным заранее размером.
В этом случае следует априори задаться неким максимально возможным размером и описать массив с этим максимально возможным размером с тем, чтобы для него в памяти было выделено нужное количество ячеек. Перед вводом массива следует ввести (или определить) его реальный размер. При этом реальный размер не должен превышать максимального (объявленного при описании). Здесь для страховки от возможной ошибки ввода может быть применена техника «ввода с защитой»:
type mass=array[1..20] of real;
var a:mass; n,k:integer;
. . . . . . . . . . . .
repeat
writeln(введите n<=20’);
read(n)
until n<=20;
writeln(введите ,n,’ чисел’);
for k:=1 to n do read(a[k]);
При введении «неправильного» n, (т.е. большего 20) цикл repeat пойдет на повторение и снова на экран выйдет запрос введите n<=20.
Вывод массива.
- В строку:
for k:=1 to n do write(a[k]);
Здесь желательно поставить формат вывода, например, write(a[k]:5:1), чтобы выводимые числа уместились на строке экрана.
- В столбец:
for k:=1 to n do writeln(a[k]);
2a. В столбец с разметкой результатов:
for k:=1 to n do writeln(a[,k,’]=’a[k]);
Пример. Дано n, массив a из n целых элементов. Преобразовать его следующим образом: положительные элементы удвоить, а отрицательные заменить нулями.
Решение. Программа:
program pr6;
type mass=array[1..50] of integer;
var a:mass; k,n:integer;
begin
repeat
writeln(введите n<=50’);
read(n)
until n<=50;
for k:=1 to n do
begin
writeln(введите a[’,k,’]’);
read(a[k]);
if a[k]>0 then a[k]:=2*a[k] else a[k]:=0
end;
writeln (новый массив’);
for k:=1 to n do writeln(a[,k,’]=’a[k]);
end.
7. Матрицы (двумерные массивы)
Двумерным массивом (матрицей) называется одномерный массив, компонентами которого являются тоже одномерные массивы (возможно, другого размера). Таким образом каждый элемент матрицы имеет два индекса. Это согласуется с математическим понятием матрицы как набора элементов, записанных в виде прямоугольной таблицы со строками и столбцами, при этом каждый элемент имеет два индекса: номер строки и номер столбца, на пересечении которых он находится.
Поскольку матрица есть массив из массивов, при работе с матрицами остаются в силе все правила работы с массивами (например, что индексы не могут быть типа real). При этом надо иметь в виду, что у матрицы имеется два размера: первый определяет количество строк, второй – количество столбцов (или количество элементов в каждой строке).
Описание матриц.
Происходит по тому же принципу, что и описание одномерных массивов. Например, вещественную матрицу размера 1020 (10 строк, 20 столбцов) можно описать следующим образом:
с определением типа матрицы:
type matr=array[1..10] of array[1..20] of real;
var a:matr;
без определения типа матрицы:
var a:array[1..10] of array[1..20] of real;
Чаще употребляют сокращенную форму:
с определением типа:
type matr=array[1..10,1..20] of real;
var a:matr;
без определения типа:
var a:array[1..10,1..20] of real;
При использовании элементов матрицы в программе индексы ставятся в квадратные скобки:
a[i][j] или a[i,j]
Ввод матрицы.
Происходит в двойных циклах.
Для примера возьмем ту же матрицу a(1020).
- поэлементно:
for i:=1 to 10 do
for j:=1 to 20 do
begin
writeln(введите a[,i,’,’,j,’]’);
read(a[i,j])
end;
2) по строкам:
for i:=1 to 10 do
begin
writeln(введите ,i,’ строку из 20 чисел’);
for j:=1 to 20 do read(a[i,j])
end;
3) по столбцам:
for j:=1 to 20 do
begin
writeln(введите ,j,’ столбец из 10 чисел’);
for i:=1 to 10 do read(a[i,j])
end;
4) единовременно:
writeln(введите матрицу 10*20’);
for i:=1 to 10 do
for j:=1 to 20 do read(a[i,j])
Замечание. В случае, если размеры матрицы (или один из них) заранее неизвестны, требуется в описании матрицы указать максимально возможные размеры, а перед вводом матрицы ввести ее реальные размеры (желательно с защитой).
Вывод матрицы в виде таблицы.
Для правильного размещения элементов матрицы на экране следует единым образом сформатировать вывод каждого элемента исходя из оценки их порядка и требуемой точности. Например, так:
for i:=1 to 10 do
begin
for j:=1 to 20 do write(a[i,j]:5:1);
writeln
end;
Пример. Даны n, квадратная вещественная матрица a(nn). Преобразовать ее следующим образом: посчитать сумму элементов, стоящих под главной диагональю и записать ее во все элементы главной диагонали.
Решение.
Пусть i означает номер строки, j – номер столбца. Главная диагональ характеризуется условием i=j. Цикл (двойной) по области под главной диагональю организуется следующим образом: внешний цикл делается по строкам (параметр i пробегает от 2 до n), внутренний цикл по j при фиксированном i (т.е. по i-й строке) начинается с j=1, а заканчивается перед элементом на главной диагонали, т.е. при j=i–1. | |
Программа.
program pr7;
type matr=array[1..20,1..20] of real;
var a:matr;
i,j,n:integer ;
s:real;
begin
repeat
writeln(введите n<=20);
read(n)
until n<=20;
for i:=1 to 20 do
begin
writeln(введите ,i, строку из ,n, чисел);
read(a[i,j])
end;
s:=0;
for i:=2 to n do
for j:=1 to i-1 do s:=s+a[i,j];
for i:=1 to n do a[i,i]:=s;
for i:=1 to n do
begin
for j:=1 to n do write(a[i,j]:7:2);
writeln
end;
end.
8. Файлы
Файловый тип представляет собой произвольной длины последовательность однотипных компонент.
Задание файлового типа:
type <имя типа>=file of <тип компонент>;
Тип компонент файла может быть любым, кроме файлового.
В то же время под файлом еще понимается поименованная область внешней памяти компьютера (либо логическое устройство – потенциальный источник или приемник информации).
Любой файл (как именованная область на диске) становится доступным программе только после выполнения процедуры открытия файла. Она заключается в связывании ранее объявленной файловой переменной с именем данного файла и его инициализации (указании направления обмена информации: чтение из файла или запись в него).
Файловая переменная связывается с именем файла с помощью стандартной процедуры assign:
assign(<ф.п.>,<имя файла>);
где:
<ф.п.> – файловая переменная,
<имя файла> – текстовое выражение, содержащее имя файла на диске.
С каждым файлом связано понятие текущего указателя, указывающего на определенную позицию в данном файле.
Инициализация файла для чтения делается с помощью стандартной процедуры reset:
reset(<ф.п.>);
При этом указатель, связанный с этим файлом устанавливается на начало файла.
Стандартная процедура
rewrite(<ф.п.>);
инициирует файл, связанный с переменной <ф.п.> для записи. Если данный файл на диске уже существовал, то он уничтожается и создается новый файл с таким же именем, при этом указатель устанавливается на начало.
Стандартная процедура
append(<ф.п.>);
инициирует запись в уже существующий файл для его расширения. При этом указатель устанавливается в конец файла. Процедура append применима только к текстовым файлам, т.е. таким, у которых файловая переменная имеет стандартный тип text (см. далее).
Текстовые файлы.
Текстовый файл представляет собой совокупность строк переменной длины. Доступ к каждой строке возможен лишь последовательно, начиная с первой. Текстовые файлы связываются с файловыми переменными, принадлежащими стандартному типу text.
Для доступа к таким файлам применяются процедуры read, readln (чтение из файла) и write, writeln (запись в файл). Первым параметром в названных процедурах должна быть файловая переменная.
Процедура read обеспечивает ввод символов, строк и чисел. Обращение:
read(<ф.п.>,<список ввода>);
При этом файл, связанный с переменной <ф.п.> должен быть предварительно инициирован (открыт) для чтения.
По исполнении процедуры read указатель, связанный с данным файлом, смещается вперед в соответствии с количеством считанных компонент файла. Повторное обращение к процедуре read обеспечит ввод начиная с позиции указателя.
Процедура readln(<ф.п.>,<список ввода> аналогична процедуре read с той разницей, что после считывания последней переменной оставшаяся часть строки пропускается, и указатель устанавливается на начало следующей строки, поэтому следующее обращение к read или readln начнется с первого символа новой строки.
Процедура write(<ф.п.>,<список ввода>) обеспечивает вывод информации в текстовый файл, связанный с переменной <ф.п.>, предварительно инициированный для записи.
Процедура writeln(<ф.п.>,<список ввода>) аналогична процедуре write с той разницей, что после вывода строки указатель устанавливается на начало новой строки, таким образом, следующее обращение к процедурам write или writeln обеспечит вывод с начала новой строки.
По окончании всех записей в файл для сохранения их на диске файл следует закрыть процедурой
close(<ф.п.>);
Если этого не сделать, записи не сохраняются!
Ввод-вывод с помощью файлов целесообразно делать в случае большого объема вводимых (выводимых) величин, например, при работе с матрицами.
Пример. Написать программу умножения матриц a(mn) и b(nk) и выполнить ее для матриц
Решение. Пусть c – результирующая матрица. Тогда c имеет размеры mk, и ее элементы вычисляются по формуле
Текст программы запишем в файл с именем pr8.pas, исходные данные – в файл pr8.dat, результаты – в файл pr8.res.
Программа.
program pr8;
type matr=array[1..20,1..20] of real;
var a,b,c:matr;
i,j,k,l,m,n:intrger;
fd,fr:text;
begin
assign(fd,pr8.dat);
assign(fr,pr8.res’);
reset(fd);
rewrite(fr);
read(fd,m,n,k);
for i:=1 to m do
for j:=1 to n do read(fd,a[i,j]);
for i:=1 to n do
for j:=1 to k do read(fd,b[i,j]);
for i:=1 to m do
for j:=1 to k do
begin
c[i,j]:=0;
for l:=1 to n do c[i,j]:=c[i,j]+a[i,l]*b[l,j]
end;
writeln(fr,произведение матриц a и b);
for i:=1 to m do
begin
for j:=1 to k do write(fr,c[i,j]:5:1);
writeln(fr)
end;
close(fr)
end.
Перед запуском программы на исполнение следует создать файл с именем pr8.dat и занести в него исходные данные в порядке чтения: сначала m, n, k, затем матрицу a и матрицу b. В нашем случае файл данных будет выглядеть следующим образом:
3 3 2
4 0 –1
7 –2 –4
5 7 9
-3 4
-4 –7
1 7
9. Записи.
Запись – это структура данных, состоящая из фиксированного числа компонентов, называемых полями записи, каждое поле именуется. В отличие от массива поля записи могут быть разных типов.
Задание типа записи:
type <имя>=record
<список имен полей с указанием типов>
end;
<список имен полей с указанием типов> представляет собой следующую конструкцию:
<поле 1>:<тип поля 1>;
<поле 2>:<тип поля 2>;
…………………………
<поле N>:<тип поля N>
В качестве примера можно рассмотреть тип записи birthday (день рождения), содержащий три поля с именами day, month и year (день, месяц и год).
type birthday=record
day:1..31;
month:1..12;
year:integer
end;
var a,b:birthday;
В этом примере переменные a, b содержат записи типа birthday. К каждому компоненту записи можно получить доступ, если указать имя переменной и затем через точку имя поля, например
a.day:=7;
b.year:=1993;
Турбо Паскаль допускает использование записи в качестве поля другой записи (иерархические записи), например
var c:record
name:string;
bd:birthday
end;
Доступ к полю year в этом случае:
c.bd.year:=1993;
Для упрощения доступа к полям записи может быть использован оператор присоединения:
with<переменная типа запись> do <оператор>;
Внутри оператора присоединения компоненты записи можно обозначать просто идентификаторами полей, например, вместо оператора
c.bd.day:=14;
можно записать
with c.bd do day:=14;
или
with c do with bd do day:=14;
или
with c,bd do day:=14;
Пример. Ввести дату своего рождения (число, месяц, год) и сегодняшнюю дату. Вычислить, сколько вам полных лет.
Решение. Вводятся две записи: bd (дата рождения) и d (сегодняшняя дата). Число полных лет z равно разности годов в случае, если дата рождения в текущем году (день и месяц) предшествует текущей дате; в противном случае число полных лет равно разности годов минус единица.
Программа.
program pr9;
type dat=record
day:1..31;
month:1..12;
year:integer;
end;
var bd,d:dat; z:integer;
begin
writeln(введите дату рождения);
with bd do
begin
write(число:_);
read(day);
write(_месяц:_);
read(month);
write(_год:_);
read(year);
end;
writeln(введите сегодняшнюю дату);
with d do
begin
write(число:_);
read(day);
write(_месяц:_);
read(month);
write(_год:_);
read(year);
end;
if (d.month>bd.month)or
(d.month=bd.month)and(d.day>=bd.day)
then z:=d.year-bd.year
else z:=d.year-bd.year-1;
writeln(число полных лет:_,z)
end.
10. Процедуры и функции
Процедуры и функции в Турбо Паскале (их еще называют подпрограммами) – это автономные программные единицы, которые спроектированы для реализации конкретных частных задач и могут быть многократно использованы в основной программе путем вызова.
Описание функции начинается с заголовка:
function <имя функции>(<список формальных параметров с указанием типов>):<тип результата>;
Список формальных параметров – это список аргументов данной функции, через которые осуществляется передача фактических параметров (реальных аргументов) в функцию. Каждый формальный параметр должен быть перечислен (в скобках после имени функции) с указанием своего типа (через двоеточие, как в обычном разделе описаний). При этом если какой-либо параметр принадлежит комбинированному типу (массив, матрица и т.д.), то этот комбинированный тип не может быть безымянным, но должен быть описан выше в разделе type.
После заголовка функции следуют разделы в том же порядке, что и в обычной программе, т.е. разделы описаний и раздел операторов. В разделе операторов должен хотя бы раз присутствовать определения результата функции, выглядящий как присвоение имени функции результата.
Замечание. Результат функции – всегда одиночная величина (не может быть комбинированного типа! – массивом, записью и т.д.)
Вызов и выполнение функции производятся путем указания в некотором выражении имени функции и далее в скобках списка фактических параметров (аргументов), которые должны соответствовать формальным, т.е. формальных и фактических параметров должно быть одинаковое количество, порядок перечисления формальных и фактических параметров должен быть один и тот же и типы соответствующих формальных и фактических параметров должны совпадать.
Пример. Даны x, y. Вычислить
где
Решение. Описываем f как функцию трех формальных аргументов – вещественных x, y и целого n. Для вычисления суммы нам потребуются две вспомогательные переменные – k и s. При вызове функции указываем фактические аргументы.
Программа.
program pr10;
var x,y,w:real;
function f(x,y:real;n:integer):real;
var k:integer; s:real;
begin
s:=0;
for k:=1 to n do s:=s+sin(k*x/10);
f:=s/sqrt(1+y*y)
end;
BEGIN
writeln(введите x,y);
read(x,y);
w:=(f(x*x,y,10)-f(1,x-y,15))/(1+f(y*y*y,cos(x),20));
writeln(w=,w)
END.
Описание процедуры также начинается с заголовка:
procedure <имя процедуры>(<список формальных параметров с указанием типов>);
С помощью параметров осуществляется передача данных в процедуру и передача результатов работы процедуры обратно в вызывающую программу. Таким образом, параметры процедуры могут быть входными и выходными. Входные играют роль аргументов функции, выходные – роль результатов, при этом в отличие от функции результатов может быть несколько, и они могут быть комбинированных типов.
В списке формальных параметров могут быть параметры-значения и параметры-переменные (перед последними ставится служебное слово var). При вызове процедуры параметры-значения передаются в процедуру по их значению, а параметры-переменные – по их имени. Основное отличие этих способов передачи параметров заключается в том, что присваивания значений параметру-переменной внутри процедуры одновременно выполняются и для соответствующей переменной внутри вызывающей программной единицы (основной программы, либо другой процедуры/функции), а при присваивании значений параметру-значению этого не происходит. Следовательно, выходные параметры (т.е. те, в которые записываются результаты работы процедуры) должны передаваться только по имени, т.е. быть параметрами-переменными (с пометкой var при описании). При вызове процедуры в качестве фактических параметров-переменных могут быть только переменные, в то время как в качестве фактических параметров-значений могут быть как переменные, так и выражения, и константы.
Вызов процедуры осуществляется с помощью оператора вызова процедуры, выглядящего как упоминание имени процедуры со списком фактических параметров, перечисленных в скобках через запятую:
<имя процедуры>(<список фактических параметров>);
с теми же условиями соответствия фактических параметров формальным, что и для функции.
Основное отличие вызова процедуры от вызова функции состоит в том, что вызов процедуры – это самостоятельный оператор, в то время как вызов функции происходит в рамках другого оператора, как правило, оператора присваивания (говоря точнее, в Турбо Паскале и вызов функции возможен в качестве самостоятельного оператора, но это выходит за рамки нашего курса).
Пример. Подсчитать куб матрицы размера 22. Умножение матриц оформить в виде процедуры.
Решение. Организуем процедуру prod с тремя параметрами-матрицами: входные a, b и выходная c, равная произведению a и b. При подсчете в основной программе матрицы b, равной кубу матрицы a, организуем вспомогательную матрицу r, равную квадрату матрицы a.
Ввод и вывод осуществляем с помощью файлов.
Программа.
program pr11;
type matr=array[1..2,1..2]of real;
var a,b,r:matr;
i,j:integer;
fd,fr:text;
procedure prod(a,b:matr;var c:matr);
begin
c[1,1]:=a[1,1]*b[1,1]+a[1,2]*b[2,1];
c[1,2]:=a[1,1]*b[1,2]+a[1,2]*b[2,2];
c[2,1]:=a[2,1]*b[1,1]+a[2,2]*b[2,1];
c[2,2]:=a[2,1]*b[1,2]+a[2,2]*b[2,2];
end;
BEGIN
assign(fd,pr11.dat);
assign(fr,pr11.res);
reset(fd);
rewrite(fr);
for i:=1 to 2 do
for j:=1 to 2 do read(fd,a[i,]]);
prod(a,a,r);
prod(a,r,b);
for i:=1 to 2 do
begin
for j:=1 to 2 do write(fr,b[i,j]:5:1);
writeln(fr)
end;
close(fr)
END.
Замечание. Переменная b означает разные вещи внутри разных программных единиц: внутри процедуры prod формальный входной параметр, а внутри основной программы – матрицу-результат. Такая ситуация в Турбо Паскале вполне допустима и адекватно распознается компьютером (в случае, когда один и тот же идентификатор по-разному описывается в разных программных единицах).