Язык программирования Паскаль

Определение данных в языке Паскаль. Особенности линейного вычислительного процесса. Характеристика разветвляющегося вычислительного процесса и условного оператора. Рассмотрение директивы компилятора и обработки ошибок ввода. Обзор открытых массивов.

Рубрика Программирование, компьютеры и кибернетика
Вид учебное пособие
Язык русский
Дата добавления 26.09.2017
Размер файла 635,7 K

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.

var x,y,z,r,t:real;

...

read (x,y,z);

r:=max(x,y);

С помощью функции вычислили максимальное из значений x, y и записали его в переменную r.

t:=max(max(x,y),z);

Максимальное из значений x, y, z записали в переменную t.

Последний вызов иллюстрирует, что, как и стандартные функции, функции, написанные программистом, могут вызываться из сколь угодно сложных выражений - при условии, что будут соблюдаться правила соответствия параметров. Написанную нами функцию max нетрудно было бы реализовать и в виде процедуры:

procedure max (a,b:real; var c:real);

begin

if a>b then c:=a

else c:=b;

end;

Однако, при вызове этой процедуры постоянно пришлось бы передавать "лишний" параметр c, служащий только для хранения возвращаемого значения.

Мы уже знакомы с оператором halt;, позволяющим аварийно (или просто из бесконечного цикла) завершить программу. Немедленно завершить текущий блок, в том числе и подпрограмму-функцию или процедуру, позволяет оператор Exit;.

Перейдем к примерам.

1. Используя подпрограмму, вычислить сумму первых k членов ряда 1+1/n.

Сумма ряда - это скаляр, естественным выглядит использование подпрограммы-функции. Применив известные алгоритмы, составим программу:

function sum (k:integer):real;

var i:integer; s:real;

begin

s:=0;

for i:=1 to k do s:=s+1/i;

sum:=s;

end;

var k:integer; s:real;

begin

write ('Введите число шагов:');

readln (k);

s:=sum(k);

writeln ('Сумма=',s:8:3);

end.

Обратите внимание - несмотря на то, что функция sum вычисляет единственную величину s, мы были бы не вправе написать в ней оператор

for i:=1 to k do sum:=sum+1/i;,

поскольку sum - это имя функции, и справа от знака присваивания оно было бы воспринято как попытка функции sum вызвать саму себя, причем, без соблюдения правил соответствия параметров. Поэтому нам понадобилась локальная переменная s.

Тем не менее, рекурсивные функции, вызывающие сами себя, существуют и будут кратко рассмотрены далее.

2. Вычислить значение выражения , где z(x)= sin 2x + ln |x|.

Очевидно, что повторное вычисление выражения z(x) с различными значениями аргумента x неэффективно, удобнее написать подпрограмму-функцию, считающую по формуле значение z(x).

function z(x:real):real;

begin

z:=sin(2*x)+ln(abs(x));

end;

begin

write ('Ответ=', (z(3)+2*sqr(z(5)))/

(z(0.1)+1):6:2);

readln;

end.

Как видно из примера, использование функции позволило выполнить расчет единственным оператором (с учетом того, что оператор writeln может печатать значения вычисленных выражений).

3. В заключение раздела скажем несколько слов о рекурсии. Рекурсивными называют функции, способные повторно вызывать сами себя. С точки зрения программирования, в этом нет ничего удивительного - просто при повторном входе в функцию в программном стеке создается ее новая копия и расчет выполняется заново с измененным значением параметра функции. Затем функция проверяет значение параметра, при необходимости изменяет его и вновь повторно вызывает сама себя. Разумеется, во избежание зацикливания, при некотором значении параметра должно быть предусмотрено завершение вычислительного процесса. Использование рекурсии целесообразно везде, где расчет следующего значения некоторой функции зависит от ее предыдущего значения. Так, классический пример на рекурсию - расчет факториала (факториал целого положительного числа n, обозначаемый n!, равен произведению всех чисел от 1 до N включительно). Используя очевидную формулу n!=n*(n-1)!, напишем следующую рекурсивную функцию:

function Factorial (n:integer):longint;

begin

if n<2 then Factorial:=1

else Factorial:=n*Factorial(n-1);

end;

Тип функции longint использован, так как факториал очень быстро растет и уже 8!=40320, то есть, больше максимального значения типа integer. Эта функция, как нетрудно увидеть, при значении аргумента, меньшем двух, возвращает единицу, а в противном случае возвращает свой аргумент n, умноженный на факториал от n-1. Несложный тест функции мог бы выглядеть так:

begin

writeln ('10!=',Factorial(10));

end.

Рекурсия удобна при составлении различного рода переборных стратегий. Так, игровая задача составления пути по "лабиринту" лучше всего решается рекурсивно, ведь всякий такой путь - это шаг плюс новый путь, уменьшенный на один шаг.

При написании рекурсивных функций следует учитывать, что рекурсивные вызовы довольно быстро заполняют стек и грозят его переполнением. Поэтому основная проблема при написании такой функции - отсечь заведомо лишние вложенные вызовы. Для этого используют дополнительные проверки условий, определяющих, целесообразно ли углублять дальше текущий уровень вложений.

18.3 Массивы в качестве параметров подпрограммы

Зачастую подпрограмма-процедура или функция должна обработать некоторый массив данных. Однако структурный тип массива нельзя непосредственно указать в списке формальных параметров. В этом случае тип массива объявляется заранее в разделе описаний с помощью подраздела type:

type ИмяТипа = ОписаниеМассива;

Здесь ИмяТипа - даваемое программистом наименование нового типа данных, а ОписаниеМассива - известный нам оператор описания вектора или матрицы. Например, если подпрограмма должна обрабатывать вещественные массивы, не превышающие по размерности десяти элементов, в разделе описаний программы имеет смысл сделать следующее объявление:

type vector = array [1..10] of real;

Поскольку новый тип данных vector предназначен для использования подпрограммами, указанное выше объявление располагается до всех подпрограмм.

В дальнейшем тип данных vector можно использовать как в разделе описания переменных

var a,b:vector;,

так и в списке формальных параметров функции или процедуры:

function work (a:vector):real;

Если по условию задачи в подпрограмме требуется при разных обращениях обрабатывать массивы различной размерности, то в разделе type объявляется тип массива с наибольшей из размерностей, встречающихся в задаче. Это чревато тем, что при обработке массивов меньшей размерности часть памяти останется неиспользованной. Кроме того, при обращении к подпрограмме в этом случае приходится отдельным параметром передавать фактическую размерность массива.

Допустим, с помощью подпрограммы требуется найти максимальные элементы матриц A3x4, B4x3, C4x5. С учетом максимальной из имеющихся размерностей, делаем объявление типа matrix в разделе описаний:

type matrix = array [1..4,1..5] of real;

Далее описываем конкретные матрицы как объекты нового типа данных matrix:

var a,b,c:matrix;

В качестве подпрограммы поиска значения максимального элемента матрицы напишем функцию max1 (функцию, а не процедуру, поскольку максимум - скалярное значение). В эту функцию нам придется передать 2 дополнительных параметра-значения, определяющих количество строк n и количество столбцов m в конкретной матрице, переданной фактическим параметром:

function max1 (n,m:integer;

var a:matrix):real;

var max:real; i,j:integer;

begin

max:=a[1,1];

for i:=1 to n do

for j:=1 to m do

if a[i,j]>max then max:=a[i,j];

max1:=max;

end;

Использование дополнительной локальной переменной max связано с теми же причинами, что в первом примере на функции. Обратите внимание, что, хотя функция max1 и не изменяет элементы своих матриц-параметров, в списке ее формальных параметров матрица указана как параметр-переменная. Для матриц и векторов это рекомендуется делать всегда, поскольку при указании параметра-переменной в матрицу передается только адрес того места памяти, где хранятся ее данные, а не копия всех элементов. В конечном счете, передача матриц и векторов формальным параметрам-переменным позволяет уменьшить размер генерируемого машинного кода.

Вызвать нашу функцию для матриц A, B и C мы могли бы так:

var ma,mb,mc:real;

...

ma:=max1(3,4,a);

mb:=max1(4,3,b);

mc:=max1(4,5,c);

Более удобную работу с массивами-параметрами предлагает механизм открытых массивов, рассмотренный в п. 18.4. Однако его непосредственно используют лишь для одномерных массивов.

Пока же рассмотрим примеры решения типовых задач.

1. Заданы вектора A и B, содержащие по 5 элементов. Используя подпрограмму, найти их скалярное произведение по формуле

Поиск скалярного произведения реализуем в виде подпрограммы-функции scal.

type vector=array [1..5] of real;

function scal (n:integer;

var a,b:vector):real;

var i:integer;

s:real;

begin

s:=0;

for i:=1 to n do s:=s+a[i]*b[i];

scal:=s;

end;

var i:integer;

a,b:vector;

s:real;

begin

writeln ('Вектор 1 из 5 элементов:');

for i:=1 to 5 do read (a[i]);

writeln ('Вектор 2 из 5 элементов:');

for i:=1 to 5 do read (b[i]);

s:=scal(5,a,b);

writeln ('s=',s:10:3);

end.

2. Сформировать по введенному с клавиатуры вектору A размерности n вектор res, компонентами которого являются отклонения элементов A от их арифметического среднего (подобная задача уже решалась выше, расширим ее на случай вектора).

Задача предполагает написание, по меньшей мере, двух подпрограмм: функция Middle будет вычислять арифметическое среднее элементов вектора, а процедура Otkl - формировать по вектору A и ранее найденному среднему mid искомый вектор отклонений b. Компоненты вектора b при этом будут вычисляться по формуле . Поскольку о размерности векторов в задаче ничего не сказано, укажем в разделе type максимальную размерность, равную 100 элементам.

type vector= array [1..100] of real;

function Middle (n:integer;

var a:vector):real;

var j:integer;

res:real;

begin

res:=0.0;

for j:=1 to n do res:=res+a[j];

Middle:=res/n;

end;

procedure Otkl (n:integer; mid:real;

var a,b:vector);

var j:integer;

begin

for j:=1 to n do b[j]:=abs(a[j]-mid);

end;

var a,res: vector;

i,n:integer;

s:real;

begin

write ('Размерность? ');

readln (n);

for i:=1 to n do begin

write ('A[',i,']=');

readln (a[i]);

end;

s:=Middle (n,a);

Otkl (n,s,a,res);

for i:=1 to n do

writeln ('res[',i,']=',res[i]:8:2);

end.

3. Используя подпрограмму, написать и проверить программу перемножения двух матриц.

Как известно, матрица A размерностью nm может быть умножена на матрицу B размерностью mp по следующей формуле: где ci,j - элемент получающейся в результате перемножения матрицы С размерностью nm. Из формулы видно, что для умножения двух матриц нам понадобится тройной цикл: внешний цикл по i перебирает строки матрицы A, вложенный в него цикл по j выбирает в матрице B очередной столбец, а самый внутренний цикл по l умножает строку матрицы A на столбец матрицы B, получая элемент ci,j. Напишем соответствующую процедуру mmul и тестовую программу для нее:

type matrix=array[1..10,1..10] of real;

var a,b,c: matrix;

i,j,n,m,p: integer;

procedure mmul (n,m,k:integer;

var a,b,c:matrix);

var i,j,l:integer; s:real;

begin

for i:=1 to n do

for j:=1 to k do begin

s:=0;

for l:=1 to m do s:=s+a[i,l]*b[l,j];

c[i,j]:=s;

end;

end;

begin

repeat

writeln;

write ('Введите количество строк ',

'1 матрицы: ');

readln (n);

write ('Введите количество столбцов ',

'1 матрицы: ');

readln (m);

write ('Введите количество столбцов ',

'2 матрицы: ');

readln (p);

until (n>1) and (n<11) and (m>1)

and (m<11) and (p>1) and (p<11);

for i:=1 to n do begin

writeln ('Введите строку ',i,

' матрицы A из',m,'элементов:');

for j:=1 to m do read (a[i,j]);

end;

for i:=1 to m do begin

writeln ('Введите строку ',i,

' матрицы B из',p,'элементов:');

for j:=1 to p do read (b[i,j]);

end;

mmul (n,m,p,a,b,c);

for i:=1 to n do begin

writeln;

for j:=1 to p do write (c[i,j]:10:3);

end;

end.

4. Процедурно ориентированные программы для распространенных задач решения системы линейных уравнений методом Гаусса, сортировки одномерного массива, поиска всех миноров второго порядка в квадратной матрице Вы можете найти и самостоятельно разобрать в Приложении 4.

5. В качестве еще одного развернутого примера на использование массивов в подпрограммах, разберем следующую задачу.

Имеется N городов, между которыми налажены пассажирские перевозки. Между какими городами самый активный пассажиропоток?

Количество городов обозначим константой cities. После математической формализации задачи, нетрудно заметить, что перевозки из города i в город j могут быть занесены в элемент матрицы ai,j, таким образом, требуется определить величину max(ai,j+aj,i), учитывая перевозки "туда" и "обратно". Для поиска максимального пассажиропотока достаточно двойного цикла с переменной границей по счетчику вложенного цикла. Как и в других программах, выделим в отдельные подпрограммы также типовые задачи ввода и вывода матрицы, а также ввода вещественного значения с контролем допустимых числовых границ ввода.

const cities=10;

type matrix=array [1..cities,1..cities]

of integer;

function max1 (n:integer; var a:matrix;

var imax,jmax:integer):integer;

var i,j,m,p:integer;

begin

m:=a[1,2]; imax:=1; jmax:=2;

for i:=1 to n do

for j:=1 to n do

if (i<>j) then begin

p:=a[i,j]+a[j,i];

if p>m then begin

m:=p; imax:=i; jmax:=j;

end;

end;

max1:=p;

end;

function readNumber (s:string;

min,max:integer):integer;

var a:integer;

begin

repeat

write (s);

{$I-}readln(a);{$I+}

if IoResult<>0 then

writeln ('Ошибка, введено не число!')

else if (a<min) or (a>max) then

writeln ('Ошибка, введенное число ',

'принадлежит интервалу [',min, ',',

max, ']')

else break;

until false;

readNumber:=a;

end;

procedure readMatrix1 (var n:integer;

var a:matrix);

var i,j:integer; s,s1:string;

begin

n:=readNumber ('Введите число строк ',

'и столбцов матрицы: ',2,cities);

for i:=1 to n do

for j:=i+1 to n do begin

s:='A['; str(i,s1); s:=s+s1+',';

str(j,s1); s:=s+s1+']=';

a[i,j]:=readNumber (s,0,maxInt);

end;

end;

procedure writeMatrix1 (s:string;

n:integer; var a:matrix);

var i,j:integer;

begin

writeln (s);

for i:=1 to n do begin

for j:=1 to n do write (a[i,j]:7);

writeln;

end;

end;

var a:matrix;

n,gorod1,gorod2:integer;

begin

readMatrix1 (n,a);

max1 (n,a,gorod1,gorod2);

writeMatrix1 ('A=',n,a);

writeln ('Самый большой пассажиропоток ',

'между городами ',gorod1,' и ',gorod2);

readln;

end.

18.4 Открытые массивы

Недостатки изученного ранее способа передачи массивов-параметров очевидны: во-первых, необходимость описания типа данных массива оператором type нарушает правило переносимости подпрограмм (действие подпрограммы становится зависимым от внешнего оператора), во-вторых, для указания реальной размерности передаваемых в подпрограмму массивов приходится использовать дополнительные параметры-значения, в-третьих, при обработке массивов меньшей, чем указано в операторе type размерности, неэффективно теряется оперативная память. В какой то мере исправить эти недостатки позволяет использование открытых массивов.

Способ подходит только для одномерных массивов. Использовать его с матрицами возможно, если интерпретировать матрицу как вектор (см. гл. 17).

Имеющиеся в программе векторы описываются в разделе var обычным способом, без определения типа type. В списке формальных параметров подпрограммы параметр-вектор указывается без диапазона размерности:

function sum(var x : array of real) : real;

При вызове подпрограммы фактический параметр-массив подставляется на место формального:

var a:array [1..5] of real;

s:real;

...

s:=sum(a);

Открытым остается вопрос - как отслеживать из подпрограммы размерность переданного массива? Для этого в Паскале существуют стандартные функции Low и High. Их единственным параметром передается идентификатор массива, Low возвращает самое низкое допустимое значение индекса, а High - самое высокое. Если A - одномерный массив, величины Low(A) и High(A) можно непосредственно применять как границы цикла for:

function sum(var x : array of real) : real;

var i:word; s:real;

begin

s:=0;

for i:=Low(x) To High(x) Do s:=s+x[I];

sum:=s;

end;

Чтобы завершить пример, вызовем написанную функцию sum:

const a:array [1..5] of real=(1,2,3,4,5.5);

begin

writeln (sum(a):6:1);

end.

Как правило, номер первого элемента открытого массива равен нулю, однако, надежнее все-таки указывать Low. Приведем пример программы, включающей подпрограмму с открытыми массивами в качестве параметров.

Найти количество элементов вектора x[7], попадающих в интервал [0, 3] и количество элементов вектора y[5], попадающих в интервал [-1, 1].

Для ввода элементов массива с клавиатуры напишем процедуру Input, которой все-таки придется передавать размерность массива-параметра (ведь вводятся два вектора различной размерности). Поэтому в Input использован тот факт, что нумерация элементов открытого массива по умолчанию выполняется в нуля. Функции kol, вычисляющей количество элементов открытого массива, попадающих в интервал [x1,x2], достаточно стандартного указания Low и High:

var x:array [1..7] of real;

y:array [1..5] of real;

k1,k2,i:integer;

procedure Input (n:integer;

var a:array of real);

var i:integer;

begin

writeln ('Enter ',n,' items of array:');

for i:=0 to n-1 do read (a[i]);

end;

function Kol (var a:array of real;

x1,x2:real):integer;

var i,k:integer;

begin

k:=0;

for i:=Low(a) to High(a) do

if (a[i]>=x1) and (a[i]<=x2) then k:=k+1;

Kol:=k;

end;

begin

Input (7,x);

Input (5,y);

k1:=Kol(x,0,3);

k2:=Kol(y,-1,1);

writeln ('k1=',k1,' k2=',k2);

end.

Процедура Input могла бы быть реализована и без передачи фактической размерности отдельным параметром:

procedure Input (var a:array of real);

var i:integer;

begin

writeln ('Enter ',High(a)-Low(a)+1,

' items of array:');

for i:=Low(a) to High(a) do read (a[i]);

end;

{ . . . }

Input (x);

Input (y);

19. Множества и перечислимые типы

Материал этой и последующих глав пособия является отчасти "факультативным", он может выходить за пределы, предусмотренные "программой-минимум" изучения основ программирования, однако, для тех, кто собирается программировать всерьез, тщательное изучение этих глав будет весьма полезным.

Множества представляют собой заранее заданные программистом наборы возможных значений переменной. Применение множеств позволяет удобно обращаться с данными, имеющими фиксированный набор возможных значений, а также облегчает проверку того, попадают ли значения в нужный диапазон.

Для объявления множества достаточно записать оператор

set of тип;

где тип - один из определенных программистом или предустановленных типов данных:

type charset: set of char;

var symbols: charset;

Вопреки этому примеру, стандартные типы данных мало применимы для множеств - ведь исходный тип набора должен быть порядковым (см. п. 2.3) и не иметь более чем 256 различных значений с нижним и верхним пределом от 0 до 255 соответственно. Это связано с тем, что для хранения количества элементов множества выделяется только один байт оперативной памяти. Приведем другой пример для множества:

type charset= set of char;

var symbols:charset;

c1:char;

begin

symbols:=['A'..'Z','a'..'z'];

write ('Put one symbol:');

readln (c1);

if c1 in symbols then writeln ('OK')

else writeln ('Error');

end.

Из примера видно, что переменным типа множества можно присваивать список диапазонов соответствующего типа (мы уже знакомились с диапазонами в п. 7.8). В дальнейшем переменная типа множества может быть использована для контроля правильности входных данных с помощью оператора in:

if c1 in symbols then writeln ('OK')

Слева от оператора in может быть указано выражение любого перечислимого типа T, а справа - набор с типом, совместимым с типом T.

Любые совместимые по типам данных множества можно объединять операций "+", вычитать операцией "-" и пересекать операцией "*". При этом результаты операций с множествами соответствуют правилам логики множеств:

порядковое значение c находится в множестве A+B только в том случае, если c находится в A или B;

порядковое значение c находится в множестве A-B только в том случае, если c находится в A и не находится в B;

порядковое значение c находится в множестве A*B только в том случае, если c находится и в A, и в B.

Если самое маленькое порядковое значение, являющееся элементом результата операции с множеством обозначить A, а самое большое - за B, то тип результата становится равным A..B.

В следующем примере множество латинских букв получается операцией сложения подмножеств латинских прописных и латинских строчных букв.

type Latin = set of 'A'..'z';

const SmallLatin : Latin = ['A'..'Z'];

BigLatin : Latin = ['a'..'z'];

var LatinLetters : Latin;

c:char;

begin

LatinLetters := BigLatin + smallLatin;

repeat

write ('Введите символ или ',

'пробел для выхода:');

reset (input);

readln (c);

if c in LatinLetters then

writeln (c,' - латинская буква');

until c=' ';

end.

Как в примере выше, полезно бывает создавать из множеств подмножества при указании конструктора, содержащего выражения диапазонов в квадратных скобках [ ... ]:

type Digits = set of 0..9; {Множество цифр}

Letters = set of 'A'..'Z';

{Множество латинских букв}

const EvenDigits : Digits =

[0, 2, 4, 6, 8];

{Подмножество четных цифр}

Vowels : Letters =

['A', 'E', 'I', 'O', 'U', 'y'];

{Подмножество гласных букв}

HexDigits : set of '0'..'z' =

['0'..'9', 'A'..'F', 'a'..'f'];

{Символы 16-ричных чисел}

type shortWeekDays =

(Pn,Vt,sr,ch,Pt,sb,Vs);

{Перечислимый тип "дни недели"}

const Holidays : set of shortWeekDays

= [sb, Vs];

{Подмножество "Выходные" дней недели}

var wd:shortWeekDays;

{Переменная типа "Дни недели"}

i:integer;

begin

wd:=Pn;

for i:=1 to 7 do begin

if wd in Holidays then

writeln (ord(wd), ' - Выходной день')

else writeln (ord(wd), ' - Будний день');

Inc(wd);

end;

end.

Тип данных shortWeekDays в этом примере является перечислимым типом. Перечислимые типы определяют упорядоченные наборы значений, перечисляя идентификаторы, которые обозначают эти значения. Их порядок следует из последовательности, в которой они были перечислены. Оператор перечисления имеет общий вид

type имя = (идентификатор,

идентификатор,..., идентификатор);

Возможные значения перечисления, заданные оператором type, должны быть идентификаторами Паскаля, поэтому назвать дни недели по-русски в последнем описании type было бы невозможно.

Идентификаторы, указанные в определении типа, становятся константами перечислимого типа, первая константа имеет порядковый номер 0, вторая - номер 1, и так далее:

type suit = (Club, Diamond, Heart, Spade);

При этом объявлении Heart является константой типа suit. Стандартная функция ord возвращает порядковый номер перечислимой константы, в нашем примере

ord(Club) = 0

ord(Diamond) = 1

ord(Heart) = 2

Как показано в листинге, переменным перечислимого типа можно присваивать константы, входящие в описание типа и увеличивать их значения как любые порядковые числа оператором Inc(wd), но эти значения нельзя читать или записывать "напрямую" операторами семейства read/write. В качестве альтернативы их можно приводить к целочисленным значениям стандартной функцией ord, при этом всегда первая константа списка имеет значение 0 (в нашем случае - константа Pn). Оператор in в листинге позволяет проверить, попадает ли величина в подмножество, созданное для элементов исходного типа множества. Таким образом, основное назначение множеств и перечислимых типов - удобная для человека запись выражений с "понятными" названиями констант вместо чисел. С точки зрения компилятора данные типа множества и перечисления являются целочисленными величинами.

Для ограничения диапазона исходных данных можно также непосредственно объявить тип-диапазон:

type Hour=0..23; minute=0..59;

Здесь объявлены переменные типов "час" и "минута", для переменных этих типов будут проверяться ограничения на попадание в указанные при описании диапазоны значений. Если переменной типа-диапазона присвоено недопустимое значение, программа отреагирует на это сообщением “Constant out of range”.

20. Обработка символьных и строковых данных

Компьютер способен обрабатывать не только числовые данные. Задачи обработки символьных данных распространены не менее, а возможно и более чем чисто арифметические расчеты. В этой главе мы изучим работу с символами и строками средствами Паскаля.

20.1 Работа с символами

Для работы с отдельными символами описываются переменные типа char:

var ch:char;

{ ... }

ch:='y';

Одна переменная типа char хранит информацию об одном коде ASCII-символа. Это можно использовать, например, для отслеживания действий пользователя по нажатию клавиш. Приведем пример одного из вариантов такой программы:

var ch:char;

begin

repeat

writeln;

write ('Продолжить? (Y/N)');

readln (ch);

if (ch='Y') or (ch='y') then begin

{Здесь программируется

нужный вычислительный процесс}

end

else if (ch='N') or (ch='n') then halt

{Завершение программы}

else writeln ('Нажмите Y или N');

until false;

end.

Для работы с кодами символов существуют 2 основных функции:

function ord(x):char;

-- возвращает ASCII-код символа x

function chr(x : byte):char;

-- возвращает символ с указанным ASCII-кодом x.

Применим последнюю функцию для того, чтобы узнать, как выглядит таблица символов кодировки DOS, используемой Паскалем:

var i,j:integer;

begin

writeln;

write ('ASCII-коды [32..255]');

for i:=2 to 15 do begin

writeln;

write (i*16:3,' ');

for j:=0 to 16 do write(chr(i*16+j),' ');

end;

writeln;

write ('ENTER для выхода...');

readln;

end.

Здесь печатаются только символы с кодами от 32 до 255 включительно, т. к. первые 32 символа с кодами от 0 до 31 - непечатаемые (например, табуляция, перевод строки).

Для определения того, попадает ли код символа в некоторый диапазон значений, удобно использовать оператор in, как это делает следующий фрагмент программы:

write ('Введите символ: '); readln (ch);

if ch in ['A'..'Z'] then

write ('Большая латинская;')

else if ch in ['a'..'z'] then

write ('Малая латинская;')

else if (ch in ['А'..'Я']) then

write ('Большая русская;')

else if (ch in ['а'..'п']) or

(ch in ['р'..'я']) then

write ('Малая русская;')

else if ch in ['0'..'9'] then

write ('Цифра;')

else write

('Это не алфавитно-цифровой символ;');

write (' Код Вашего символа= ',ord(ch));

Работая с алфавитными символами, приходится отдельно учитывать ввод строчных и прописных букв. Удобнее сначала преобразовать все символы к прописным с помощью функции upcase:

var ch:char; i:integer;

begin

repeat

for i:=1 to random(72) do write ('*');

writeln;

write ('Продолжить? (Y/N)');

readln (ch);

until upcase(ch)='N';

end.

К сожалению, эта функция бесполезна при работе с символами русского и других национальных алфавитов, для ее замены напишем и протестируем собственную подпрограмму c названием upcase_ru:

procedure upcase_ru (var s:string);

var i,l,c:integer;

begin

l:=length(s);

for i:=1 to l do begin

c:=ord(s[i]);

if (c>=ord('а')) and (c<=ord('п'))

then c:=c-32

else if (c>=ord('р')) and (c<=ord('я'))

then c:=c-80;

s[i]:=Upcase(chr(c));

end;

end;

var s:string;

begin

writeln ('Введите строку текста:');

readln (s);

upcase_ru (s);

writeln ('Преобразованная строка:');

writeln (s);

end.

Программа учитывает, что в кодировке DOS не все символы кириллицы закодированы идущими подряд числами (см. Приложение 1).

Кроме того, в программе уже применяется массив символов, которому в Паскале соответствует тип данных string (строка). Мы упоминали этот тип данных, но еще не работали с ним. Как раз строкам посвящен п. 20.2.

20.2 Работа со строками

Строка - это массив символов, т. е., элементов типа char. Нумерация символов в строке всегда выполняется с единицы. В Паскале строке соответствует тип данных string. Строка описывается оператором следующего вида:

var Имя_строки : string [длина];

Если положительная целочисленная величина "длина" не указана, выделяется память под строку длиной до 255 символов. Приведем примеры описания строк:

var s1:string;

s2:string[20];

s3:array [1..20] of string;

Здесь s1 - строка с длиной по умолчанию, s2 - строка из 20 символов, s3 - массив из 20 строк, каждая из которых может занимать до 256 байт памяти (дополнительный байт нужен для хранения длины строки).

Со строками можно выполнять операцию присваивания. Покажем это на примере описанных выше строк.

s1:='А.И. Иванов';

-- строке s1 присвоено значение строковой константы.

s1[3]:='В';

-- отдельному символу строки s1 присвоили символьную константу.

s2:='2009';

-- строке s2 присвоили строку, являющуюся записью целого числа. Позднее такая строка может быть преобразована в число стандартной процедурой Val.

s3[1]:='Информатика';

s3[2]:='';

-- s3 является строковым массивом. Его первому элементу присвоена строковая константа, второму - пустая строка.

Для ввода строк с клавиатуры следует применять оператор readln, т. к. ввод строки должен завершиться нажатием клавиши Enter:

writeln ('Введите имя пользователя:');

readln (s1);

Для вывода строк на экран или принтер можно использовать как оператор write, так и writeln:

s2:='SUMMA';

write (s2) ;

-- на экран будет выведена строка "SUMMA".

writeln ('Сумма':10);

-- будет выведена строка "_____Сумма" (5 пробелов перед словом) и курсор переведен на следующую строку экрана.

Оператор сложения "+" переопределен для строк таким образом, что выполняет их сцепление (конкатенацию):

s1:='2009' + ' год'; s2:='н.э.';

s3[3]:=s1+' '+s2;

После этих действий значение строки s1 будет равно ''2009_год", а строка s3[3] - ''2009_год_н.э.".

Если при сложении строк превышена максимальная длина результирующей строки, лишние символы отсекаются. Для сцепления строк можно также использовать стандартную функцию concat.

Операция отношения "=" позволяет посимвольно сравнить строки. При этом действуют следующие правила:

строки считаются равными только при одинаковом наборе символов и одинаковой длине;

иначе происходит поэлементное сравнение символов по их кодам. При этом, согласно таблице ASCII-кодов (см. Приложение 1) старшинство отдельных символов следующее: '0' < '1' < ... < '9' < 'A' < ... < 'Z' < 'a' < ... < 'z' < символы кириллицы.

Остальные операции отношения также применимы к строкам.

В ядро Паскаля включен ряд стандартных подпрограмм для обработки строковых данных. Опишем их прототипы, то есть, перечислим заголовки подпрограмм с указанием типа и количества формальных параметров.

function Length (s:string):integer;

-- определяет и возвращает длину строки s в символах;

function copy

(s:string; N,L:integer): string;

-- возвращает часть строки s длиной L символов, начиная с позиции N;

procedure Insert

(s0:string; var s: string; N: integer);

-- в строку s вставляет строку s0, начиная с позиции N;

procedure Delete

(var s:string; N,L:integer);

-- в строке s удаляет L символов, начиная с позиции N;

function Pos (s0, s:string): integer;

-- возвращает позицию, начиная с которой строка s0 содержится в строке s или значение 0, если s0 не содержится в s;

procedure str (x: числовой; var s:string);

-- преобразует число x в строку s, параметр x может иметь любой числовой тип;

procedure Val (s:string;

var x: числовой; var error:integer);

-- преобразует строку s в число x. Параметр x может иметь любой числовой тип. Параметр-переменная error служит для контроля правильности преобразования. Если преобразовать удалось, то error=0, иначе error будет равен номеру первого непреобразуемого символа строки s.

Приведенных стандартных подпрограмм достаточно для решения большинства несложных задач, связанных с обработкой текстовых данных. Рассмотрим ряд типовых задач на примерах.

1. Разобрать предложение на слова и вывести каждое слово на новой строке экрана.

Алгоритм работы этой программы очень прост - до тех пор, пока в исходной строке предложения s есть хотя бы один пробел, вся часть строки до пробела копируется в строковую переменную w (слово). Если пробелов уже нет (или не было изначально), то вся строка - это одно слово. После обработки очередного слова (в нашем случае - это вывод его на новую строку экрана оператором writeln) обработанная часть строки вместе с пробелом удаляются из s - чтобы следующий шаг цикла не нашел то же самое слово.

var s,w:string; {предложение и слово}

p:integer; {позиция пробела}

begin

writeln ('Введите текст');

readln (s);

repeat

p:=pos (' ',s);

if p>0 then w:=copy (s,1,p-1)

else w:=s;

writeln (w);

delete (s,1,p);

until p=0;

end.

Приведенная программа имеет ряд недостатков. Самый заметный из них - не учтены дополнительные пробелы между словами, которые будут восприниматься программой как лишние "пустые слова". Избавимся от них с помощью следующего примера.

2. Удалить лишние пробелы между словами.

Алгоритм решения задачи также несложен. Пока в строке есть два подряд идущих пробела, следует удалять один из них. После этого остается проверить, нет ли в начале и конце строки по одному лишнему пробелу. Приведем только основную часть программы:

repeat

p:=pos (' ',s);

if p>0 then delete (s,p,1);

until p=0;

if s[1]=' ' then delete (s,1,1);

if s[length(s)]=' ' then

delete (s, length(s),1);

writeln (s);

Однако, в примерах 1 и 2 есть более существенный недостаток - проходы по строке неоднократны, тогда как разбор на слова можно сделать и за один цикл сканирования строки. Попытаемся реализовать это в следующей программе.

3. Разобрать предложение на слова за один цикл сканирования строки.

Приведем полный текст программы, а затем - комментарии.

var s,word:string;

c,c0:char;

i,l,start:integer;

inword:boolean;

begin

writeln ('Enter string:');

reset (input); readln (s);

s:=' '+s+' ';

l:=Length (s);

inword:=false;

for i:=2 to l do begin

c0:=s[i-1];

c:=s[i];

if (c0=' ') and (c<>' ') then begin

inword:=true;

start:=i;

end;

if c=' ' then begin

if inword=true then begin

word:=copy (s,start,i-start);

writeln ('''',word,''' is word');

end;

inword:=false;

end;

end;

end.

По сути дела, у нашей программы всего 2 состояния - внутри слова и вне его. Переключением состояний управляет флаг inword. Номер символа, с которого начинается очередное слово, запоминается в переменной start. Программа не учитывает знаки препинания и возможность разделения слов другими символами, кроме пробела. Тем не менее, избавившись еще и от функции copy, совершающей лишний проход по части строки (например, сразу же накапливая слово word по мере сканирования), можно было бы получить действительно эффективный алгоритм. Как обычно, платой за эффективность алгоритма является сложность программы.

4. Подсчитать количество пробелов в строке.

Это пример реализует работу со строкой как с массивом символов.

var s:string; k,i:integer;

begin

writeln ('text?');

readln (s);

k:=0;

for i:=1 to length (s) do

if s[i]=' ' then k:=k+1;

writeln ('k=',k);

end.

21. Текстовые файлы

Для написания большинства сложных программ требуется обмен данными с файлами. В этой главе мы рассмотрим только текстовые файлы, для работы с бинарными и типизированными файлами см. специальную литературу и гл. 22.

21.1 Общие операции

Для работы с каждым файлом описывается переменная типа text:

var f:text;

Ее называют файловой переменной. Если программа обрабатывает несколько файлов одновременно, для каждого из них описывается такая переменная. Можно использовать и одну переменную для нескольких файлов, если они обрабатываются последовательно, и каждый следующий файл открывается после завершения работы с предыдущим. Вся работа с файлом происходит через файловую переменную, имя файла указывается только один раз следующим оператором:

assign (f,'имя_файла');

где f - ранее описанная файловая переменная.

Этот оператор предшествует открытию файла и связывает переменную с файлом на жестком или гибком диске. В качестве имени файла может быть указан абсолютный или относительный путь к файлу на жестком или сменном диске:

assign (f,'data.txt');

- будет открываться файл с именем data.txt из текущей папки;

assign (f,'a:\my.dat');

- будет открыт файл с именем my.dat из корневой папки дискеты.

Имя файла также может быть введено пользователем с клавиатуры:

var name:string; f:text;

begin

writeln ('Введите имя файла:');

readln (name);

assign (f,name);

Наконец, имя файла можно передать программе параметром командной строки (см. п. 5.3).

После связывания следует открыть файл. Каждый файл может быть открыт только в одном из трех режимов - для чтения данных, для записи новых данных (при этом, если файл уже существовал, его прежнее содержимое будет стерто) или для добавления данных в конец файла. Если требуется сначала прочитать данные из файла, а потом переписать этот же файл, следует открыть файл для чтения, после чтения закрыть его и вновь открыть для записи. Открытие файла выполняется одним из трех операторов:

reset (f); - открыть для чтения;

rewrite (f); - открыть для записи;

append (f); - открыть для добавления.

Чтение или запись данных осуществляется знакомыми нам операторами read, readln, write и writeln, но первым параметром этих стандартных процедур указывается имя файловой переменной:

var a,b,c:real; f1,f2:text;

begin

assign (f1,'read.txt');

assign (f2,'write.txt');

reset (f1);

{открыли файл read.txt для чтения,}

rewrite (f2);

{а файл write.txt для записи}

read (f1,a,b);

{Прочитали 2 числа из файла read.txt}

c:=(a+b)/2;

writeln (f2,c:6:2); {записали значение c

и перевод строки в файл write.txt}

После того, как все операции с файлом выполнены, его следует закрыть, особенно если происходила запись или добавление данных:

close(f);

-- закрыли файл, связанный с файловой переменной f.

При работе с файлами могут возникнуть ошибки, связанные как с отсутствием нужного файла на диске, так и с проблемами чтения или записи (например, мы пытаемся открыть файл для записи на защищенном диске). Поэтому операторы открытия файла и чтения или записи данных следует защищать директивой компилятора {$I-}...{$I+}, а после оператора проверять статус операции ввода-вывода с помощью стандартной функции IoResult:

var f:text; name,s:string;

begin

writeln ('Введите имя файла:');

readln (name);

assign (f,name);

{$I-}reset(f);{$I+}

if IoResult<>0 then begin

writeln ('Не могу открыть файл ',name,

' для чтения!');

writeln ('Нажмите Enter для выхода');

readln;

halt;

end;

readln(f,s);

writeln ('Первая строка файла:');

writeln (s);

close(f);

writeln ('Нажмите Enter для выхода');

readln; end.

В дальнейшем мы для краткости не всегда будем выполнять эти проверки, но хороший стиль программирования предполагает, что в своих программах вы будете их делать.

При чтении из файлов зачастую объем читаемых данных неизвестен заранее. Поэтому необходима функция, умеющая определять, прочитаны ли уже все данные:

function Eof(var F : text) : boolean;

- возвращает true, если при чтении достигнут конец файла.

function Eoln (var F : text) : boolean;

- возвращает true, если при чтении достигнут конец строки.

Как правило, основной цикл чтения файла с заранее неизвестным количеством строк выглядит так:

while not eof (f) do begin

{операторы для чтения строк файла

и работы с ними}

end;

При чтении из одного файла "смешанных" строковых и числовых данных следует проверять, действительно ли в нужных строках файла содержатся числа. Для этого можно использовать стандартную процедуру val. Как правило, формат файлов, понимаемых той или иной программой, выбирается программистом, и важно предусмотреть реакцию программы на ошибочный формат исходных данных. Допустим, наша программа представляет собой простейший телефонный справочник, включающий имена абонентов и по одному телефонному номеру на каждое имя. Формат файла, хранящего данные справочника, также выберем простейшим:

Фамилия1

Номер1

Фамилия2

Номер2

и т. д., то есть, в строках 1, 3, 5, ... файла содержатся фамилии абонентов, а в строках 2, 4, 6, ... - их номера телефонов. Примем также, что файл справочника называется phones.txt, существует и находится в той же папке, откуда запускается программа. Полный листинг программы приводится ниже.

var f:text;

name,phone,search:string;

number,strings:longint;

error:integer;

found:boolean;

begin

assign (f,'phones.txt');

reset(f);

writeln (Фамилия абонента для поиска:');

readln (search);

strings:=1; {Счетчик прочитанных строк}

found:=false; {Переключатель

"найдено"-"не найдено"}

while not eof(f) do begin

readln (f,name); {Прочитали фамилию}

readln (f,phone); {Прочитали номер}

val (phone,number,error); {Пробуем

номер-строку преобразовать в число}

if error<>0 then begin {если это

не удалось сделать - ошибка}

writeln('Ошибка - нет номера телефона!',

' Номер строки=', strings);

writeln ('Нажмите Enter для выхода');

reset (input); readln; halt;

end;

if name=search then begin

writeln ('Телефон найден:',number);

found:=true;

break;

end;

strings:=strings+1;

end;

close (f);

if found=false then

writeln ('Телефон не найден!');

writeln ('Нажмите Enter для выхода');

reset (input); readln;

end.

Этой учебной программе недостает как умения редактировать открываемый ей справочник, так и гибкости при поиске - например, она различает как разные символы строчные и прописные буквы во вводимой фамилии.

21.2 Примеры работы с файлами

Рассмотрим несколько типовых задач на обработку текстовых файлов.

1. Чтение числовых данных из файла. Массив данных имеет фиксированную размерность, примем ее равной 5.

var f,w:text;

a: array [1..5] of integer; i:integer;

begin

assign (f,'data.txt');

reset (f);

for i:=1 to 5 do read (f, a[i]);

close (f);

assign (w, 'result.dat');

rewrite (w);

writeln (w,'Результаты:');

for i:=1 to 5 do

writeln (w,a[i]:5,sqr(a[i]):5);

close(w); end.

Файл с именем data.txt может быть, например, таким:

1 2 3

4 5

Файл результатов result.dat будет таким:

Результаты:

1 1

2 4

3 9

4 16

5 25

2. Просмотр любого текстового файла на экране. По заполнении экрана до 24 строк программа делает паузу.

var f:text; s:string; count:integer;

begin

repeat

write ('Имя файла или 0 для выхода: ');

readln (s);

if s='0' then halt;

assign (f,s);

{$I-}reset (f);{$I+}

if IoResult<>0 then begin

writeln ('Не могу открыть файл ',s);

write ('Нажмите Enter для продолжения');

readln;

continue; {повторяем цикл с начала}

end;

count:=1;

while not eof(f) do begin

readln (f,s);

writeln (s);

count:=count+1;

if count=24 then begin

count:=1;

write('Нажмите Enter для продолжения');

readln;

end;

end;

write ('Нажмите Enter для нового ввода');

readln;

close (f);

until false;

end.

Строка s здесь используется как для ввода имени файла, так и для чтения строки файла - ведь после выполнения связывания оператором assign имя файла нам больше не нужно. Обратите внимание также на оператор continue, в данном случае он позволяет не завершать выполнение программы после неверного ввода пользователя.

3. Работаем со "смешанным" файлом данных, строки которого содержат значения разных типов.

Пусть файл data.txt имеет следующий вид:

Иванов 2

Петров 1

Сидоров 3

Попов 2

...

В каждой строке файла находится фамилия рабочего и через пробел - номер участка, на котором он работает.

Напишем программу для вывода фамилий всех работников выбранного участка и подсчета их количества.

var f:text; s,fam:string;

u,uch,p,kol,i:integer;

begin

writeln ('Участок?'); read (uch);

assign (f,'data.txt'); reset (f);

kol:=0;

while not eof (f) do begin

readln (f,s);

p:=pos(' ',s);

if p>0 then begin

fam:=copy (s,1,p-1);

delete (s,1,p);

val (s,u,i);

if i<>0 then begin

writeln ('Ошибка в числе ',s,

' - нет номера участка');

halt;

end;

if u=uch then begin

{подсчет рабочих на участке}

writeln (fam);

kol:=kol+1;

end;

end

else begin

writeln ('Ошибка в строке ',s,

' - нет пробела');

halt;

end;

end;

close (f);

writeln ('kol=',kol);

end.

Значительная часть этой программы посвящена анализу прочитанной из файла строки "смешанных" данных. Программу можно существенно упростить, изменив формат исходных данных - например, на одной строке файла может быть набрана фамилия, а на другой - номер участка. Тогда основной цикл чтения файла будет выглядеть так:

while not eof (f) do begin

readln (f,fam);

readln (f,u);

if (u=uch) then begin

{ обработка }

end;

end;

Приведенный пример иллюстрирует, как часто выбор программистом более или менее удобного формата хранения данных влияет на сложность программы.

21.3 Работа с параметрами командной строки

Программа в DOS или Windows может запускаться с параметрами командной строки, через которые обычно передают имена файлов или указывают режимы работы программы:

turbo.exe vasya.pas

-- здесь программе Турбо Паскаль передано имя файла vasya.pas;

my /s /a

-- программе с именем my переданы параметры /s и /a.

Существует две стандартных функции для работы с параметрами:

Paramcount - вернет общее число параметров командной строки;

Paramstr(i) - вернет строку, содержащую параметр номер i.

В качестве примера реализуем программу просмотра текстового файла на экране, которой параметром передается имя нужного файла.

var fil:text; name:string;

begin

if Paramcount<>1 then begin

writeln ('Запускайте так: ',

'FILEVIEW имя_файла');

halt; end;

assign (fil,Paramstr(1));

reset (fil);

while not eof(fil) do begin

readln (fil,name);

writeln (name);

end;

end.

Второе полезное свойство функции Paramstr - вызванная из исполняемого файла с аргументом 0, она возвращает полный путь к нему.

Из оболочки Турбо Паскаля параметры командной строки можно передать запускаемой программе через пункт Parameters меню Run.

22. Записи. Бинарные файлы

Как и массивы, записи относятся к составным типам данных. Запись состоит из фиксированного числа элементов, называемых полями. Каждое поле представляет собой объект простого типа данных - как правило, строку или число. Существенно то, что в одну запись могут входить поля различного типа, в отличие от массива, все элементы которого однотипны. Например, записью можно считать строку экзаменационной ведомости:

Борисова Ю.А. 4 5 5

Данная запись состоит из четырех полей: одно поле - строкового типа (фамилия и инициалы студента), остальные три поля - числовые (оценки студента по трем дисциплинам).

Описанию переменной типа запись предшествует определение типа с помощью оператора type. Для нашей записи это описание могло бы выглядеть следующим образом:

type zap = record

fam: string;

m, inf, h: integer;

end;

Здесь zap - имя нового типа данных, а fam, m, inf и h - имена полей записи. Служебные слова record ... end в данном случае играют роль операторных скобок, внутри которых записываются поля записи с указанием их типов.

Не очень удобно то, что для каждой дисциплины введено отдельное поле. Введем тип данных student, где эта проблема решена использованием в качестве поля массива balls (баллы студента по трем дисциплинам):

type student = record

fam: string;

balls: array [1..3] of integer;

end;

После сделанного таким образом определения в разделе описания переменных можно объявить переменную типа "запись":

var str: student;

или массив таких переменных:

var students: array [1..20] of student;

Для обращения к отдельным полям переменной типа запись используется селектор записи - символ точки, разделяющий наименования записи и поля:

str.fam

-- обращение к полю "фамилия" записи str;

students[1].fam

-- обращение к полю "фамилия" первого элемента массива записей students;

students[i].balls[2]

-- вторая оценка i-го элемента массива записей students.

С полем записи, как и с элементом массива, разрешены все допустимые в языке операции над переменной соответствующего типа.

Для того чтобы узнать объем в байтах, занимаемый записью в оперативной памяти или на жестком диске, следует воспользоваться стандартной функцией sizeof, передав ей в качестве аргумента имя типа записи:

sizeof (student) - вернет размер памяти в байтах, занимаемый одной записью типа student.

Чаще всего записи используются при работе с базами данных, хранящимися на жестком диске. Мы уже умеем читать и записывать текстовые файлы, но хранение записей в текстовом файле, как правило, неудобно и требует каждый раз сложного разбора прочитанных строк. Поэтому для эффективной работы с файлами записей следует познакомиться с остальными типами файловых переменных Паскаля.

В общем виде файл данных в Паскале представляет собой совокупность однотипных компонент. В зависимости от способа объявления файловой переменной можно выделить три вида файлов.

Типизированные файлы. Для них тип компонент указывается непосредственно в описании файловой переменной. Описание в этом случае имеет вид: var файловая_переменная: file of тип_компонент_файла;

Например, если компоненты файла имеют тип записи zap, то разделе описания переменных можно объявить файловую переменную следующим образом:

var f: file of zap;

Естественной "порцией данных" для такого файла будет одна запись типа zap, что очень удобно. Типизированный файл может быть объявлен и как совокупность записей простого типа:

var f2: file of real;

Здесь объявлен файл, содержащий вещественные числа во внутреннем представлении. Размер одной записи такого файла будет равен 6 байт (размер памяти, отводимый под величину типа real).

Нетипизированные файлы. Задаются стандартным типом file без указания типа компонент, например:

var f: file;

Чтение и запись данных в такой файл может осуществляться произвольными "порциями" данных, что удобно, например, при организации временных и буферных файлов. Рассмотрение нетипизированных файлов выходит за рамки нашего курса.

Текстовые файлы. Знакомые нам по гл. 21 текстовые файлы задаются стандартным типом text, например:

var f: text;

Компонентами текстового файла являются строки переменной длины. После ввода каждой строки нажимается клавиша Enter. Исторически сложилось так, что при этом в конец каждой строки дописывается два невидимых символа: символ с кодом 13 (CR, возврат каретки) и символ с кодом 10 (LF, перевод строки). Доступ к строкам осуществляется последовательно, начиная с первой. Число строк в текстовом файле может быть произвольным. Последним символом файла может быть специальный маркер EOF (End Of File) с кодом #26.

Существенно подчеркнуть то, что первый и второй вид файлов - бинарные, а не текстовые:

Текстовый файл содержит только алфавитно-цифровые символы и ряд специальных (такие, как возврат каретки, перевод строки, табуляция). Содержимое файла непосредственно доступно для чтения в любом редакторе текста или в окне консоли.

Бинарный файл содержит произвольные символы, чаще всего он представляет собой набор данных в машинном коде и недоступен для непосредственного чтения.

Например, следующая несложная программа объявляет бинарный файл, состоящий из вещественных чисел и записывает в него числа от 1 до 10 включительно:

var f:file of real; r:real;

begin

assign (f,'real.dat');

rewrite (f);

r:=1;

while r<11 do begin

write (f,r); r:=r+1;

end;

close (f);

end.

Так как размер величины типа real в памяти равен 6 байтам, полученный файл real.dat будет иметь размер 60 байт и содержать внутренние машинные представления указанных чисел (рис. 22.1).

Рис. 22.1. Бинарный файл

Никакого "текстового" смысла в этой записи нет, чтобы ее интерпретировать, нужно открыть файл в редакторе, поддерживающем 16-ричное "машинное" представление чисел или дамп (рис. 22.2).

Рис. 22.2. Шестнадцатеричный дамп бинарного файла

В этом представлении видно, что каждое число занимает по 6 байт.

Переписав программу так, чтобы числа писались в текстовом представлении, получаем следующее:

var f:text; r:real;

begin

assign (f,'real.txt');

rewrite (f);

r:=1;

while r<11 do begin

write (f,r); r:=r+1;

end;

close (f);

end.

Файл real.txt состоит из одной строки (так как мы писали только оператором write), в этой строке приведены вещественные числа в экспоненциальной форме (поскольку мы не указывали ширину и точность вывода). Файл изображен на рис. 22.3.

Рис. 22.3. Текстовый файл

Размер файла real.txt равен 170 байт, он текстовый и его можно открыть в "Блокноте" Windows.

Важно усвоить и то, что для бинарных файлов не имеет смысла понятие "строки текста". Поэтому чтения и запись при работе с бинарными файлами осуществляются только процедурами read и write, но не readln и writeln.

Все изученные нами ранее приемы и средства работы с файлами (кроме цикла с функцией eof), вообще говоря, применимы лишь к текстовым файлам, так как существенно зависели от понятия строки данных. Для работы с бинарными файлами необходимы иные средства, позволяющие удобно перемещаться по их записям.

...

Подобные документы

  • Язык программирования Турбо Паскаль. Запись алгоритма на языке программирования и отладка программы. Правила записи арифметических выражений. Стандартное расширение имени файла, созданного системным редактором. Составной оператор и вложенные условия.

    курсовая работа [75,0 K], добавлен 21.03.2013

  • Особенности программирования на языке Паскаль в среде Турбо Паскаль. Линейные алгоритмы, процедуры и функции. Структура данных: массивы, строки, записи. Модульное программирование, прямая и косвенная рекурсия. Бинарный поиск, организация списков.

    отчет по практике [913,8 K], добавлен 21.07.2012

  • Иерархическая структура производного типа данных в языке Паскаль. Определение массива как упорядоченного набора фиксированного количества некоторых значений. Сортировка одномерных и двумерных массивов методом простых обменов, простым выбором и включением.

    курсовая работа [48,8 K], добавлен 27.11.2010

  • История и основы структурного программирования в среде Turbo Pascal. Работа с различными типами данных. Операторы языка. Работа с символьными и строковыми переменами, одномерным, двумерным массивами. Классификация компьютерных игр. Игры на языке Паскаль.

    курсовая работа [28,8 K], добавлен 06.05.2014

  • Логические конструкции в системе программирования Паскаль. Команды языка программирования, использование функций, процедур. Постановка и решение задач механики в среде системы Паскаль. Задачи статики, кинематики, динамики решаемые с помощью языка Паскаль.

    курсовая работа [290,9 K], добавлен 05.12.2008

  • Общая характеристика языков программирования. Описание языка Паскаль: основные субъекты языка; структура Паскаль-программы; типизация и объявление данных. Операторы присваивания и выражения. Структурные операторы, организация ветвлений и циклов.

    дипломная работа [276,6 K], добавлен 26.01.2011

  • Сравнительный анализ языков программирования высокого уровня Си и Паскаль. Реализация алгоритма обработки данных. Тестирование и отладка программы или пакета программ. Структура программы на языке Турбо Паскаль. Указатели и векторные типы данных.

    курсовая работа [233,5 K], добавлен 14.12.2012

  • Изучение символьных и строковых типов данных, алгоритма задачи на языке программирования Паскаль. Описания получения и установки отдельного символа строки, изменения регистра символов. Анализ создания и просмотра файла, поиска и сортировки информации.

    курсовая работа [440,7 K], добавлен 13.06.2011

  • Совместимость и преобразование типов данных. Создание информационно-поисковой системы на языке программирования Паскаль. Описание интерфейса, каждого блока программы "Картотека больных". Рассмотрение результатов работы программы, сортирования данных.

    курсовая работа [368,9 K], добавлен 18.05.2015

  • Изучение основных конструкций и способов написания программ на языке Паскаль. Обзор принципов работы и интерфейса написанной программы. Обработка и модификация двумерных массивов. Файловые структуры данных. Текстовые файлы. Элементы машинной графики.

    курсовая работа [761,7 K], добавлен 11.03.2015

  • Приобретение теоретических и практических навыков программирования на языке Паскаль. Математическая формулировка задачи и выбор метода обработки информации. Разработка алгоритма и его описание. Описание программы. Форма представления исходных данных.

    курсовая работа [224,3 K], добавлен 11.02.2016

  • Основные сведения о системе программирования Турбо Паскаль. Структура программы на Паскале и ее компоненты. Особенности и элементы языка Турбо Паскаль. Порядок выполнения операций в арифметическом выражении, стандартные функции и оператор присваивания.

    лекция [55,7 K], добавлен 21.05.2009

  • Рассмотрение общих сведений и уровней языков программирования. Ознакомление с историей развития, использования языков программирования. Обзор достоинств и недостатков таких языков как Ассемблер, Паскаль, Си, Си++, Фортран, Кобол, Бейсик, SQL, HTML, Java.

    курсовая работа [759,5 K], добавлен 04.11.2014

  • Выбор метода проектирования транслятора с языка Паскаль на язык Си, разработка и кодирование алгоритма программы. Использование допустимых операторов в исходном тексте, определение типов переменных и синтаксиса логических и арифметических выражений.

    курсовая работа [1,0 M], добавлен 03.07.2011

  • Основы создания фрактальных композиций при помощи среды программирования Паскаль. Сущность и основа фрактальной графики. Графические возможности и операторы для рисования геометрических фигур в среде Паскаль. Примеры обозначения цветов на языке Паскаль.

    лабораторная работа [15,7 K], добавлен 12.06.2010

  • Понятие программы и ее основные составляющие. Операторы ввода и вывода. Разветвляющиеся алгоритмы. Цикл как многократное выполнение одинаковых действий. Особенности использования оператора выбора. Графики функций и системы координат. Рекурсия и анимация.

    презентация [663,7 K], добавлен 24.12.2010

  • Изучение организации диалоговой программы и закрепления основных элементов программирования на языке Паскаль и Си (Delphi, C++ Builder). Описание представления информации в программах на языках высокого уровня. Сравнительная характеристика Delphi и C++.

    курсовая работа [3,1 M], добавлен 27.02.2015

  • Алгоритмы и алфавит языка Турбо Паскаль. Основные типы данных. Операторы присваивания, перехода и выбора. Понятие массива в Паскале. Особенности работы со строками в программе. Использование линейного поиска и поиска с барьером. Основные виды сортировок.

    учебное пособие [53,2 K], добавлен 09.11.2009

  • Создание транслятора, обрабатывающего код программы на языке Паскаль и за счет эквивалентных операторов генерирующего программу на Си. Особенности внешней спецификации и работы лексического анализатора. Структура программы, вывод результатов на экран.

    курсовая работа [254,0 K], добавлен 02.07.2011

  • Расчет на устойчивость в системе программирования Турбо Паскаль. Определение критического напряжения стержня по формуле Ясинского, предельной гибкости в зависимости от материала. Программирование алгоритма расчета. Порядок ввода исходных данных.

    курсовая работа [1,0 M], добавлен 27.04.2013

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.