
pascal_lections
.pdfS:=’Супер строка’;
insert(‘длинная ’,S,7); {‘Супер длинная строка’}
End.
Function length (S: string) :integer;
Функция возвращает текущую длину строки S.
Function pos (subst: string; S: string): byte;
Функция отыскивает место первого вхождение подстроки subst в строку S. Возвращает номер позиции, где начинается найденная подстрока. Если подстрока не найдена, возвращает 0.
Procedure str (X [:Width [:Decimals]]; var S:string);
Процедура преобразования числа Х любого целого или вещественного типа в строку символов.
Procedure val (S; var X; var code:integer);
Процедура преобразования строки S во внутреннее представление числа X (целое или вещественное). Code – код ошибки. Code=0, если преобразование успешно завершилось; иначе Code= номер символа, на котором произошла ошибка преобразования.
Var I, Code :integer; S :string;
Begin S:=’что-то-там__как-то-там’;
Val(S,I,Code); If Code<>0 then
writeln('Error at position ', Code) else
writeln(‘Value = ’, I);
End.
Function UpCase (ch: char) :char;
Функция преобразовывает символ ch в соответствующую заглавную букву, если ch является строчной буквой латинского алфавита. Для остальных символов значение не меняется.
Function chr (X: byte) :char;
Функция возвращает символ из таблицы символов, в соответствии с заданным номером X.
Function ord (ch :char) :longint;
Функция возвращает порядковый номер символа ch в таблице символов.
var |
|
|
x:real; |
|
|
y:integer; |
|
|
s, s1:string; |
|
|
begin |
|
|
s:=concat('12','345'); |
s=’12345’ |
|
s1:=copy(s,3,length(s)-2); |
s1=’345’ |
|
insert('+',s1,2); |
s1=’3+45’ |
|
delete(s,pos('2',s),3); |
s=’15’ |
|
str(789,s); |
s=’789’ |
|
val('3.14',x,y); |
x=3.14 |
y=0 |
val('3,14',x,y); |
x=0 |
y=2 |
end. |
|
|
41
Файлы и файловые переменные.
Опр.: Файл – линейная последовательность элементов, каждый из которых имеет тип элемента (или тип записи) файла. Каждый элемент файла имеет номер. Первый элемент файла имеет нулевой индекс.
ВПаскале имеются три класса файлов:
-типизованный файл
-текстовый файл,
-нетипизованный файл.
Описание файловой переменной:
Var F: file of тип_файла;
F1: file of integer; |
- типизированный файл |
F2: file; |
- нетипизированный файл |
F3: text; |
- текстовый файл |
Перед использованием: файловая переменная должна быть связана с внешним файлом с помощью вызова процедуры Аssign.
Внешним файлом обычно является поименованный файл на диске, но он также может представлять собой устройство, например, порт, клавиатуру или дисплей. Во внешних файлах сохраняется записанная в файл информация, или они служат источниками информации, которая считывается из файла.
Когда связь с внешним файлом установлена, файловая переменная должна быть «открыта». Существующий файл можно открыть с помощью процедуры Reset, а новый файл можно создать и открыть с помощью процедуры Rewrite.
Текстовые файлы, открытые с помощью процедуры Reset доступны только для чтения, а открытые с помощью процедуры Rewrite – только для записи.
Типизованные и нетипизованные файлы всегда допускают как чтение, так и запись, независимо от того были они открыты с помощью процедуры Reset или Rewrite.
Когда начинается выполнение программы, всегда автоматически открываются стандартные текстовые файловые переменные Input и Оutput (ввод и вывод). Input – это доступный только для чтения файл, связанный с клавиатурой. Оutput – это доступный только для записи файл, связанный с дисплеем.
Обычно доступ к файлам организуется последовательно, то есть, когда элемент считывается с помощью стандартной процедуры Read или записывается с помощью стандартной процедуры Write, текущая позиция файла перемещается к следующему по порядку элементу файла.
К типизованным и нетипизованным файлам можно организовать прямой доступ с помощью процедуры Sееk, которая перемещает текущую позицию файла к заданному элементу. Для определения текущей позиции в файле и текущего размера файла можно использовать функции
FilePos и FileSize.
Когда программа завершает обработку файла, он должен закрываться с помощью процедуры Close. После полного закрытия файла, связанный с ним внешний файл обновляется. Затем файловая переменная может быть связана с другим внешним файлом.
42
Перечень процедур и функций, которые могут использоваться для всех файлов:
Procedure |
Assign |
присваивает имя внешнего файла файловой переменной |
Procedure |
ChDir |
выполянет смену текущего каталога |
Procedure |
Close |
закрывает открытый файл |
Function |
EOF |
возвращает для файла состояние end-of-file (конец файла) |
Procedure |
Erase |
стирает внешний файл |
Procedure |
GetDir |
возвращает текущий каталог на заданном диске |
Function |
IOResult |
возвращает целое значение, являющееся состоянием последней |
|
|
выполненной операции ввода-вывода |
Procedure |
MkDir |
создает подкаталог |
Procedure |
Rename |
переименовывает внешний файл |
Procedure |
Reset |
открывает существующий файл |
Procedure |
Rewrite |
создает и открывает новый файл |
Procedure |
RmDir |
удаляет пустой подкаталог |
Типизированные файлы. Процедура Seek.
Типизированными файлами называются дисковые файлы, состоящие из нумерованной последовательности объектов некоторого типа. Так как длина каждого объекта постоянна, то можно вычислить позицию каждого объекта в файле и напрямую считать или записать этот объект.
Пример 1. Создает файл, содержащий квадраты 10 чисел типа real.
Program FileEx3;
Var file1: file of real; R: real;
N: integer; Begin
Assign(file1,’data.dat’);
Rewrite(file1); For N:=1 to 10 do Begin
R:=sqr(N);
Write(file1,R); {запись числа в файл в двоичном внутреннем формате}
End;
Close(file1);
End.
Пример 2. Считывает с экрана числа в диапазоне от 1 до 10 и выдает их квадраты, записанные в файле
Program FileEx4; Var
File1 :file of real; R: real;
N: integer; Begin
Assign(file1,’data.dat’);
Reset(file1);
Write(‘введите число (1-10) : ’);
Readln(N); //While N>0 do //Begin
Seek(file1,N-1); {передвигаем указатель текущей позиции файла в заданное место}
Read(file1,R);
Writeln(‘квадрат ’,N,’ равен ’,R);
//End;
End.
43
Seek(var имя_файла; номер_компоненты :longint)
Процедура передвигает текущую позицию файла в заданную позицию. Отсчет ведется по количеству типизированных компонент, начиная с нулевого индекса.
Процедуры BlockRead и BlockWrite.
Процедуры BlockRead и BlockWrite аналогичны по смыслу процедурам Read и Write, однако они работают на с отдельными записями, а с наборами записей.
BlockRead(var имя_файла :file; var буфер; размер: word [; var результат :word]) – считывает одну или более записей из файла в буфер.
BlockWrite(var имя_файла :file; var буфер; размер: word [; var результат :word]) – записывает одну или более записей из буфера в файл.
Имя_файла – нетипизированная файловая переменная.
Буфер – любая переменная, в которую происходит считывание или из которой происходит запись. Размер – выражение типа word, определяющее число записей для считывания или записи. Результат – переменная типа word, определяющая результат операции.
Пример копирования файлов из одного в другой, блоками 2 Кб.
var
FromF, ToF: file;
NumRead, NumWritten: Word; Buf: array[1..2048] of Char;
begin
Assign(FromF, ParamStr(1)); { Open input file } Reset(FromF, 1); { Record size = 1 } Assign(ToF, ParamStr(2)); { Open output file } Rewrite(ToF, 1); { Record size = 1 }
Writeln('Copying ', FileSize(FromF), ' bytes...'); repeat
BlockRead(FromF, Buf, SizeOf(Buf), NumRead); BlockWrite(ToF, Buf, NumRead, NumWritten);
until (NumRead = 0) or (NumWritten <> NumRead); Close(FromF);
Close(ToF);
end.
Процедуры Erase и Rename.
Процедуры Erase и Rename работают с внешними файлами.
Erase(var file_name :file) – удаляет файл.
Rename(var file_name :file; new_file_name :string) – переименовывает файл.
Пример. Переименовывает файл, используя в качестве обоих имен содержимое командной строки, затем уничтожает.
Program FileEx7; var
F1: file; BEGIN
if ParamCount<>2 then writeln('wrong parameters') else
begin assign(F1,ParamStr(1));
writeln('rename: ',ParamStr(1),' into ',ParamStr(2));
44
rename(F1,ParamStr(2));
erase(F1);
end;
END.
Текстовые фалы
Текстовые фалы являются разновидностью типизированных файлов типа file of char. Для описания текстовых файлов используется предопределенный тип text.
Var TextFile : text;
В текстовых фалах помимо признака конца файла EOF (код символа = 26, Ctrl-Z), присутствует еще признак конца строки EOLN, состоящий на самом деле из последовательности двух символов: «возврат каретки» (код символа = 13) и «перевод строки» (код символа = 10).
Отличия файла text от file of char:
1.автоматическое преобразование числовых данных в цепочку символов при записи значений в файл, и обратное преобразование символов, являющихся числами, в числовое значение при выполнении операции чтения в переменные соответствующих числовых типов.
2.текстовые файлы не имеют прямого доступа, то есть к ним не применимы процедуры seek, blockread и blockwrite.
3.присутствует признак конца строки.
4.для чтения/записи текстовых файлов разрешается использовать процедуры readln и writeln, которые недопустимы для остальных типов файлов.
Пример. Подсчет среднего числа символов в строке в текстовом файле с последовательным доступом.
Program SymbolsCount; Var ch:char;
LineCount,CharCount:longint;
F:text; BEGIN
LineCount:=0;
CharCount:=0;
Assign(F,ParamStr(1));
Reset(F);
While not EOF(F) do Begin
While not EOLN(F) do Begin
Read(F,ch);
inc(CharCount);
end;
ReadLn(F); {переход на следующую строку} inc(LineCount);
end;
Close(F);
if LineCount=0 then writeln(‘пустой файл’) else
begin
writeln(‘число строк = ’, LineCount:6); writeln(‘число символов = ’, CharCount:6); writeln(‘среднее число символов в строке = ’,
CharCount/LineCount:1:4);
end;
END.
45
Один и тот же физический файл можно писать/читать как типизированный файл различных
типов.
Пример. Сначала в файл типа CHAR записывается ряд символов, а затем этот же физический файл открывается как файл типа BYTE, и на печать выводятся коды ASCII, записанных в него символов.
Program CharToByte. Uses crt;
Var
F1 : file of char;
F2 : file of byte; C : char;
B : byte; BEGIN
Clrscr;
Assign(F1,’test.dat’);
Rewrite(F1);
For C:=’0’ to ‘9’ do write(F1,C); For C:=’A’ to ‘J’ do write(F1,C);
Close(F); {-----------}
Assign(F2,’test.dat’);
Reset(F2);
While not EOF(F2) do Begin
Read(F2,B);
Write(B:4);
End;
Close(F2);
END.
Пример. Программа сортировки файла с прямым доступом методом простого обмена (метод «пузырька»)
Program FileSort; Uses crt;
Var
F : file of integer; X, Y : integer;
I, J : longint; BEGIN
clrscr; {$I-}
Assign(F, ‘sort.dat’);
Reset(F); {$I+}
if IOResult<>0 then begin
writeln(‘ошибка открытия файла’); halt(1);
end;
clrscr;
writeln(‘исходный файл:’); for I:=1 to FileSize(F) do begin
Read(F,X);
46
Write(X:8);
End;
WriteLn;
Close(F); {-----------} Reset(F);
For I:=FileSize(F)-1 downto 1 do
{«всплывание» очередного макс. элемента на i–ю позицию} for J:=0 to I-1 do
begin seek(F,J); read(F,X,Y); if X>Y then begin
seek(F,J);
write(F,Y,X);
end;
end;
Close(F); {-----------} Reset(F);
WriteLn(‘отсортированный файл:’);
For I:=1 to FileSize(F) do Begin
Read(F,X);
Write(X:8);
End;
Close(F);
END.
Имея открытую файловую переменную можно получить имя файла
uses strings, dos;
var f:text; FileName: string; begin
assign(f,'text.txt');
rewrite(f); writeln(f,'Hello, world!'); close(f);
FileName:=StrPas(PChar(@TextRec(f).Name)); writeln(FileName);
end.
GetFAttr(var имя_файла; var атрибут: word) – возвращает атрибуты файла SetFAttr(var имя_файла; var атрибут: word) – устанавливает атрибуты файла
Постоянная |
Значение |
ReadOnly |
$01 |
Hidden |
$02 |
SysFile |
$04 |
VolumeID |
$08 |
Directory |
$10 |
Archive |
$20 |
AnyFile |
$3F |
FSplit(путь:PathStr; var каталог:DirStr; var имя:NameSrt; var расширение:ExtStr); - разбиение полного имени файла на составляющие (путь, имя, расширение)
FExpand(путь :PathStr) :PathStr; - расширяет имя файла до полного имени.
FSearch(путь:PathStr; список_каталогов:String) :PathStr; - ищет файл в списке каталогов. Каталоги в списке должны быть отделены двоеточием
Тип строки |
Определение |
ComStr |
String[127] |
PathStr |
String[79] |
DirStr |
String[67] |
47
NameStr |
String[8] |
ExtStr |
String[4] |
FilePos(var имя_файла) :longint; – возвращает текущую позицию для заданного файла FileSize(var имя_файла) :longint; – возвращает текущий размер файла
Truncate(var file_name) – обрезает файл от текущей позиции до конца
EOF(var file_name) :Boolean – =true, если указатель стоит на символе конца файла EOLN(var file_name) :Boolean – =true, если указатель стоит на символе конца строки
Записи.
Запись, в отличие от массивов, множеств и файлов, является составной структурой данных. Если отдельно взятый массив, множество или файл всегда включает в себя элементы одного типа, то записи могут объединять в единое целое любое число структур данных других типов: простых переменных, массивов, множеств и записей. Но не допускается использование полей записи файлового типа. В вариантных записях допускается использование только того варианта полей, который соответствует установленной константе поля-признака.
Фиксированные записи Обычная фиксированная запись состоит из одного или нескольких полей, для каждого из которых указывается имя и тип.
Type
String10 = string[10];
String20 = String[20];
TStudentCard = record
SurName :string20; {фамилия}
Name :string20; {имя}
FatherName :string20; {отчество}
Year :integer; {год.рожд.}
HomeAddress :string; {адрес}
GroupCode : string10; {группа}
Predmet = record {оценки за последний семестр}
MatAn,
Programming,
Phylos :byte;
End;
End;
Обращение к полям записей осуществляется с помощью уточненных (квалифицируемых) идентификаторов, в которых указывается вся цепочка имен от идентификатора типа «запись» до идентификатора требуемого поля. Имена полей квалифицируемого идентификатора разделяются точками.
type
TGroup = array [1..25] of TStudentCard; Var
Group3056, Group3051 :TGroup;
В этом случае будут корректны следующие обращения к полям:
Group3056[1].Name := ’Sergey’;
Group3056[1].Year := 1980; Group3056[1].Predmets.MatAn := 5; Group3051[6] := Group3051[5];
48
Для упрощения работы с записями в Pascal имеется специальный оператор присоединения
with.
С использованием этого оператора вышеприведенные операторы будут записаны в таком
виде:
With Group3056[1] do
Begin
Name := ‘Sergey’;
Year := 1980;
Predmet.MatAn := 5;
End;
Group3051[6] := Group3051[5];
При заполнении информацией структур типа «запись» с помощью процедур Read и Raedln, необходимо помнить, что допускается ввод только некоторых стандартных типов данных. Поэтому, в процедурах Read и readln могут располагаться идентификаторы только самых внутренних полей записи.
Вариантные записи.
Рассмотренный выше тип TStudentCard включает несколько оценок за пердметы. Но в других семестрах будут другие предметы. Возникает проблема: в записи TStudentCard нас интересуют оценки за последний семестр, но в каждом семестре сдаются новые предметы. Если использовать обычные фиксированные записи, то придется в тип TStudentCard включать поля для всех изучаемых предметов. Это приводит к избыточности информации в типе TStudentCard и снижению читабельности кода программы. Кроме того, будет неэкономно использоваться память, поскольку для каждого студента память будет выделяться под все поля всех оценок, а фактически будут использоваться только несколько полей, описывающих оценки по предметам за последний семестр.
В таких случаях целесообразно использовать вариантные записи, в которых описываются поля для всех возможных случаев, но альтернативные группы полей разграничиваются более наглядно и память выделяется только под конкретный, необходимы в данный момент вариант.
type
TPredmetSemestr1 = record
MatAn1, {математический анализ} Programming1, {программирование} Phylos :byte; {философия}
End;
TPredmetSemestr2 = record
MatAn2,
Electronica,
Programming2,
Geometry :byte;
End;
TStudentCard = record
{фиксированная часть записи}
SurName :string20; {фамилия} Name :string20; {имя}
FatherName :string20; {отчество} Year :integer; {год.рожд.} HomeAddress :string; {адрес} GroupCode : string7; {группа}
{вариантная часть записи} case Semestr :byte of
49
1: (
Sem1 :TPredmetSemestr1;
);
2: (
Sem2 :TpredmetSemestr2;
);
End;
Var
Group3056, Group3051 :TGroup;
...
with Group3056[3] do begin
{заполнение фиксированной части записи} SurName := ‘Иванов’;
Name := ‘Иван’; FatherName := ‘Иванович’;
Year := 1980;
HomeAddress := ‘г.Вырица, ул.Ленина, д.2, кв.3’;
GroupCode := ‘3056’;
{заполнение вариантной части записи} Semestr:=1; {установка признака семестра}
With Sem1 do Begin
MatAn1 := 3; Programming1 := 4; Phylos := 5;
End;{with sem1} End;{with group3056}
НО В вариантных записях НЕ ДОПУСКАЕТСЯ ИСПОЛЬЗОВАТЬ одинаковые имена идентификаторов для вариантных компонент записи.
пример не корректен:
TStudentCard = record
...
{вариантная часть записи} case Semestr :byte of
1:( MatAn, LineAlgebra, Programming, Phylos :byte; );
2:( MatAn, Electronic, Programming, Geometry :byte; );
End;
Будет выдана ошибка ‘Duplicate identifier (MatAn)’
50