Paskal_uchebn_posob_chast2_26_6_7
.pdf51
BEGIN REWRITE (СПИСОК,'IMY.TXT');
WRITE ('вводи длину строки =>'); READLN(N);WRITELN('вводи фамилии =>'); FOR I:=1 TO N DO
BEGIN WHILE NOT EOLN DO
BEGIN READ(C); WRITE(список С) END; (* переход к новой строке *)
READLN; WRITELN( список ) END;
CLOSE( список ) end.
В этой программе требуется построить файл,представляющий собой список группы.Удобно сделать так,чтобы в каждой строке файла записывалась одна фамилия. При вводе каждая фамилия начинается с новой строки.
Программа S1 записывает во внешний файл с именем imy.txt фамилии, вводимые с терминала, а программа S2 считывает из каждой
строки внешнего файла фамилию и выводит ее на терминал с новой строки.
PROGRAM S2(INPUT);
TYPE семестр=FILE OF CHAR;
VAR список,семестр;
C:CHAR;I:INTEGER;
BEGIN RESET(список,'IMY','TXT');
WHILE NOT EOF(список) DO BEGIN
WHILE NOT EOLN(список) DO BEGIN
READ(список,C);
WRITE(C); END
READLN(список); WRITELN;
END END.
Стандартные файлы INPUT и OUTPUT являются текстовыми и в программе их описывать не надо, т.к.они описаны как текстовые файлы:
TYPE TEXT=FILE OF CHAR
VAR INPUT,OUTPUT:TEXT
При обращении к стандартным процедурам READ,READLN,WRITE,WRITELN в качестве стандартного аргумента можно указывать имя любого текстового файла. Если имя файла не указано, то происходит обращение к стандартному файлу.
PDF created with pdfFactory Pro trial version www.pdffactory.com
52
ЗАДАЧА
Написать программу, которая читает фамилии и пять оценок и записывает суммарный балл в текстовый файл.
Program result(input,output); Uses crt;
Const imf='res.dat'; Var fio:string;
summa:0..100; ball:0..20; schet:1..5; simvol:char; fres:text;
Begin clrscr;
assign(fres,imf);
rewrite(fres); repeat
writeln('Введите ФИО'); readln;
read(fio);
writeln(fres,fio);
summa:=0;
for schet:=1 to 5 do begin
write('Результат='); readln(ball); summa:=summa+ball;
end;
writeln(fres,summa);
writeln('Есть ли еще студенты (y/n)'); read(simvol)
until simvol='n';
writeln('*** Программа завершена ***');
close(fres);
End.
ЗАДАЧА
Написать программу, которая изображает данные,хранящиеся в текстовом файле предыдущей программы.
Program izres;
PDF created with pdfFactory Pro trial version www.pdffactory.com
53
Const imf='res.dat'; Var fio:string;
summa:0..100; simvol:char; fres:text;
Begin assign(fres,imf); reset(fres);
write('Для изображения очередной записи нажмите клавишу tab'); while not eof(fres) do
begin read(simvol);
readln(fres, fio, summa); writeln(fio,'сумма=',summa:3);
end;
writeln('*** Достигнут конец файла ***');
End.
ЗАДАЧА
Написать программу, которая считывает записи и заносит их в файл, а затем печатает их по порядку (телефонный справочник) .
Program tel; Uses crt;
Type dan=record fio:string; adres:string; nomer:string;
end;
Var spisok:file of dan; simvol:char;a:dan;
Procedure chten(var tekzap:dan); Begin
with tekzap do begin
writeln('Введите ФИО'); readln(fio); writeln('Введите адрес'); readln(adres); writeln('Введите номер телефона'); readln(nomer);
end;
End;
PDF created with pdfFactory Pro trial version www.pdffactory.com
54
Procedure izobr(tekzap:dan); Begin
with tekzap do begin
writeln(fio); writeln(adres); writeln('телефон',nomer); end;
End;
Begin clrscr;
assign(spisok,'acd.dat');
rewrite(spisok); repeat chten(a);
write(spisok,a);
write('Есть ли еще записи(y/n)'); readln(simvol);
until simvol='n'; close(spisok); reset(spisok);
while not eof(spisok) do begin
write('Для изображения следующей записи нажмите клавишу
ENTER');
readln;
read(spisok,a);
izobr(a);
{ get(spisok) } end;
writeln('*** Конец записей ***');
End.
PDF created with pdfFactory Pro trial version www.pdffactory.com
55
ЛЕКЦИЯ 1, 2 для 2-го семестра 1 курса УКАЗАТЕЛИ И ДИНАМИЧЕСКАЯ ПАМЯТЬ
Динамическая память.
Все переменные, обьявленные в программе, размещаются в одной непрерывной области оперативной памяти, которая называется сегментом данных. Длина сегмента данных определяется архитектурой микропроцессора 8086 и составляет 65536 байт, что может вызвать известные затруднения при обработке больших массивов данных. С другой стороны, обьем памяти ПК (обычно не менее 640 Кбайт)
достаточен для успешного решения задач с большой размерностью данных. Выходом из положения может служить использование так называемой динамической памяти.
Динамическая память - это оперативная память ПК, предоставляемая программе при ее работе, за вычетом сегмента данных (64 Кбайт), стека (обычно 16 Кбайт) и собственно тела программы. По умолчанию этот размер определяется всей доступной памятью ПК и,как правило, составляет не менее 200...300 Кбайт.
Динамическая память- это фактически единственная возможность обработки массивов данных большой размерности. Многие практические
задачи трудно или невозможно решить без использования динамической памяти. Такая необходимость возникает, например ,при разработке систем автоматезированного проектирования (САПР): размерность математических моделей, используемых в САПР, может значительно отличаться в разных проектах; статическое (т.е. на этапе разработки САПР) распределение памяти в этом случае, как правило, невозможно.
Наконец, динамическая память широко используется для временного
запоминания данных при работе с графическими и звуковыми средствами ПК.
Динамическое размещение данных означает использование динамической памяти непосредственно при работе программы. В отличие от этого статическое размещение осуществляется компилятором Турбо- Паскаля в процессе компиляции программы. При динамическом размещение заранее не известны ни тип, ни количество размещаемых данных, к ним нельзя обращаться по именам, как к статическим переменным.
PDF created with pdfFactory Pro trial version www.pdffactory.com
56
Оперативная память
0 |
|
ОС |
|
||
|
100-130Кб |
|
Паскаль+прога |
64Кб |
|
|
|
|
|
Динамическая память |
|
|
640 |
|
|
|
|
|
1024Кб |
|
|
||
|
|
|
Адреса и указатели.
Оперативная память ПК представляет собой совокупность элементарных ячеек для хранения информации - байтов, каждый из которых имеет собственный номер. Эти номера называются адресами, они позволяют обращаться к любому байту памяти.
Турбо Паскаль предоставляет в распоряжение программиста гибкое средство управления динамической памятью- так называемые указатели.
Указатель- это переменная, которая в качестве своего значения содержит адрес байта памяти.
В ПК адреса задаются совокупностью двух шестнадцатиразрядных слов, которые называются сегментом и смещением.
Сегмент- это участок памяти, имеющий длину 65536 байт (64 Кбайт) и начинающийся с физического адреса, кратного 16 (т.е.0,16,32,48
и т.д.).
Смещение указывает, сколько байт от начала сегмента необходимо пропустить, чтобы обратиться к нужному адресу.
Адресное пространство ПК составляет 1 Мбайт (речь идет о так называемой основной памяти ПК; на компьютерах класса IBM PC/AT адресное пространство составляет 16 Мбайт; такие ПК могут иметь до 15 Мбайт дополнительной памяти, однако в Турбо Паскале нет средств, поддерживающих работу с дополнительной памятью). Для адресации в пределах 1 Мбайта нужно 20 двоичных разрядов, которые получаются из двух шестнадцатиразрядных слов (сегмента и смещения) следующим образом: содержимое сегмента смещается влево на 4 разряда, освободившиеся правые разряды заполняются нулями, результат складывается с содержимым смещения.
Фрагмент памяти в 16 байт называется параграфом, поэтому можно сказать, что сегмент адресует память с точностью до параграфа, а смещение- с точностью до байта. Каждому сегменту соответствует
PDF created with pdfFactory Pro trial version www.pdffactory.com
57
непрерывная и отдельно адресуемая область памяти. Сегменты могут
следовать в памяти один за другим без промежутков или с некоторым интервалом, или, наконец, перекрывать друг друга.
Таким образом, по своей внутренней структуре любой указатель представляет собой совокупность двух слов (данных типа WORD),трактуемых как сегмент и смещение. С помощью указателей
можно размещать в динамической памяти любой из известных в Турбо Паскале типов данных. Лишь некоторые из них
(BYTE,CHAR,SHORTINT,BOOLEAN) занимают во внутреннем представлении один байт, остальные - несколько смежных. Поэтому на самом деле указатель адресует лишь первый байт данных.
Объявление указателей.
Как правило, в Турбо Паскале указатель связывается с некоторым типом данных. Такие будем называть типизированными. Для обьявления типизированного указателя используется значок ^, который помещается перед соответствующим типом, например:
type
PerconPointer = ^PerconRecord; PerconRecord = record
Name : string; Job : string;
Next : PerconPointer end;
var
p1 : ^integer;
p2 : ^real;
Обратите внимание: при обьявлении типа PERCONPOINYER мы сослались на тип PERCONRECORD, который предварительно в программе объявлен не был. Как уже отмечалось, в Турбо Паскале последовательно проводиться в жизнь принцип, в соответствии с которым перед использованием какого- либо идентификатора он должен быть описан.
Исключение сделано только для указателей, которые могут ссылаться на еще не обьявленный тип данных. Это исключение сделано не случайно. Динамическая память дает возможность реализовать широко
используемую в некоторых программах организацию данных в виде списков. Каждый элемент списка имеет в своем составе указатель на соседний элемент, что обеспечивает возможность просмотра и коррекции списка. Если бы в Турбо Паскале не было этого исключения, реализация списков была бы значительно затруднена.
PDF created with pdfFactory Pro trial version www.pdffactory.com
58
1-ый элемент |
|
2-ой элемент |
|
… |
|
Последний |
списка |
|
списка |
|
|
|
Элемент |
|
|
|
|
|||
|
|
|
|
|
|
Списка |
|
|
|
|
|
|
|
указатель |
|
указатель |
|
|
|
NIL |
|
|
|
|
|
|
|
Пример списочной структуры данных
В Турбо Паскале можно обьявлять указатель и не связывать его при этом с каким-либо конкретным типом данных. Для этого служит стандартный тип POINTER, например:
var
pp : pointer;
Указатели такого рода будем называть нетипизированными.
Поскольку нетипизированные указатели не связаны с конкретным типом, с их помощью удобно динамически размещать данные, структура и тип которых меняются в ходе работы программы.
Значениями указателей являются адреса переменных в памяти, поэтому следовало бы ожидать, что значение одного указателя можно передавать другому. На самом деле это совсем не так.
В Турбо Паскале можно передавать значения только между указателями, связанными с одним и тем же типом данных. Если, например,
var
p1, p2 : ^integer; p3 : ^real;
pp : pointer;
то присваивание
p1 := p2;
вполне допустимо, в то время как p1 := p3;
запрещено, поскольку p1 и p3 указывают на разные типы данных. Это ограничение, однако, не распространяется на нетипизированные указатели, поэтому мы могли бы записать
pp := p3; p1 := pp;
и тем самым достичь нужного результата.
Все дело в том, что любое ограничение, с одной стороны, вводится для повышения надежности программ, а с другой - уменьшает мощность языка, делает его менее пригодным для каких- то применений. В Турбо
PDF created with pdfFactory Pro trial version www.pdffactory.com
59
Паскале немногочисленные исключения в отншении типов данных придают языку необходимую гибкость, но их использование требует от
программиста дополнительных усилий и таким образом свидетельствует о вполне осознанном действии.
Выделение и освобождение динамической памяти.
Вся динамическая память в Турбо Паскале рассматривается как сплошной массив байтов, который называется кучей. Физически куча располагается в старших адресах сразу за областью памяти, которая занимает тело программы.
Начало кучи хранится в стандартной переменной HEAPORG , конец- в переменной HEAPEND. Текущую границу незанятой динамической памяти указывает указатель HEAPPTR.
0 |
|
|
|
|
Старшие адреса |
640 |
||||||
Системная область |
Программа |
|
|
|
|
КУЧА |
|
|
Системная область |
|||
|
|
|
|
|
||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
HeapOrg |
|
|
|
|
|
|
|
|
|
|
|
|
|
HeapPtr |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
HeapEnd |
|
|
|
|
|
|
|||
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
|
||||||
Память под |
любую |
динамически размещаемую |
переменную |
выделяется процедурой NEW. Параметром обращения к этой процедуре является типизированный указатель. В результате обращения указатель приобретает значение, соответствующее динамическому адресу, начиная с которого можно разместить данные, например:
var
i, j : ^integer; r : ^real; begin new(i);
.....
После выполнения этого фрогмента указатель I приобретает значение, которое перед этим имел указатель кучи HEAPPTR, а сам HEAPPTR увеличивает свое значение на 2, так как длина внутреннего представления типа INTEGER, с которым связан указатель I, составляет 2 байта (на самом деле это не совсем так: память под любую переменную выделяется порциями, кратными 8 байтам). Оператор new(r); вызовет еще раз смещение указателя HEAPPTR, но теперь уже на 6 байт, потому что
PDF created with pdfFactory Pro trial version www.pdffactory.com
60
такова длина внутреннего представления типа REAL. Аналогичным образом выделяется память и для переменной любого другого типа.
После того, как указатель приобрел некоторое значение, т.е. стал указывать на конкретный физический байт памяти, поэтому адресу можно разместить любое значение соответсвующего типа. Для этого сразу за указателем без каких-либо пробелов ставится значок ^, например:
i^ := 2; {в область памяти i помещено значение 2}
r^ := 2*pi; {в область памяти r помещено значение 6.28}
Таким образом, значение, на которое указывает указатель, т.е. собственно данные размещены в куче, обозначается значком ^, который ставится сразу над указателем. Если за указателем нет значка ^, то имеется ввиду адрес, по которому размещены данные. Имеет смысл еще раз задуматься над только что сказанным: значением любого указателя является адрес, а чтобы указать, что речь идет не об адресе, а о тех данных, которые размещены по этому адресу, за указателем ставится ^.
Динамически размещенные данные можно использовать в любом месте программы, где это допустимо для констант и переменных соответствующего типа, например:
r^ := sqr(r^) + i^ - 17;
Разумеется, совершенно недопустим оператор
r := sqr(r^) + i^ - 17;
так как |
указателю |
R нельзя присвоить |
значение вещественного |
выражения. Точно так же недопустим оператор |
|
||
r^ := sqr(r); |
|
|
|
поскольку значением R является адрес, и его (в отличие от того значения, |
|||
которое |
размещено |
по этому адресу) нельзя возводить в квадрат. |
Ошибочнным будет и такое присваивание: r^ := i;
так как вещественным данным, на которые указывает R^, нельзя присвоить значение указателя (адрес).
Динамическую память можно не только забирать из кучи, но и возращать обратно. Для этого используется DISPOSE. Например,
операторы
dispose(r);
dispose(i);
вернут в кучу 8 байт, которые ранее были выделены указателям I и R (см.выше).
Отметим, что процедура DISPOSE (PTR) не изменяет значение указателя PTR, а лишь возращает в кучу память ранее связанную с этим указателем. Однако повторное применение процедуры свободному
PDF created with pdfFactory Pro trial version www.pdffactory.com