- •050201 «Системная инженерия»
- •Содержание
- •Цели и задачи практики
- •Структура отчета по практике
- •3 Задание №2 Сортировка массива указателей
- •Задание № 1 Сортировка массива записей
- •Постановка задачи
- •Прямые методы сортировки. Краткие теоретические сведения
- •Сортировка прямым включением
- •Сортировка прямым выбором
- •Сортировка прямым обменом (метод пузырька)
- •Задание № 2 Сортировка массива указателей на записи
- •Постановка задачи
- •Краткие теоретические сведения
- •Пример программы
- •Приложение а Пример файла с информацией о студенческой группе
Краткие теоретические сведения
Статической переменной (статически размещенной) называется описанная явным образом в программе переменная; обращение к ней осуществляется по имени. Место в памяти для размещения статических переменных определяется при компиляции программы.
В отличие от таких статических переменных в программах, написанных на языке Pascal, могут быть созданы динамические переменные. Основное свойство динамических переменных заключается в том, что они создаются и память для них выделяется во время выполнения программы. Размещаются динамические переменные в динамической области памяти (heap - области).
Динамическая переменная не указывается явно в описаниях переменных и к ней нельзя обратиться по имени. Доступ к таким переменным осуществляется с помощью указателей.
Указатель – это переменная, значением которой является адрес другой переменной определенного типа, называемого базовым типом.
Множество значений переменной-указателя состоит из адресов ячеек памяти и специального значения NIL, которое ни на что не указывает. NIL не является реальным адресом, а означает отсутствие ссылки на какой-либо объект. Не путайте со случаем, когда значение указателя не определено, NIL – вполне определенное значение.
Для обращения к значению переменной, адрес которой хранится в указателе, применяется операция разыменования (разадресации), обозначаемая с помощью символа ^ справа от имени указателя.
Работа с динамической областью памяти в Pascal реализуется с помощью процедур New и Dispose.
Процедура New(p) выделяет место в динамической области памяти для размещения динамической переменной p^ и ее адрес присваивает указателю p.
Процедура Dispose(p) освобождает участок памяти, выделенный для размещения динамической переменной процедурой New, и значение указателя p становится неопределенным.
Порядок работы с динамической переменной:
– создать (отвести для нее место в динамической памяти;
– работать с ней при помощи указателя (ее адреса в памяти);
– удалить (освободить занятое этой переменной место).
Приведенный ниже пример покажет работу с динамическими переменными и указателями:
var p1,p2:^real; {описание указателей на динамическую переменную типа real (конкретный тип нужен для определения размера)}
...
New(p1); {создать динамическую переменную и присвоить указателю p1 значение ее адреса}
p1^:=3.1415; {заполнение динамической переменной}
p2:=p1; {теперь указатель p2 показывает на ту же переменную}
writeln(p2^); {можно в этом убедиться, распечатав ее значение}
dispose(p1); {удалить переменную, освободив динамическую память}
Пример программы
Пусть требуется составить программу, создающую и обрабатывающую текстовый файл, содержащий фамилии и средние баллы студентов. Пример файла приведен ниже.
Аношенко Г. 4.0
Ракаускайте К. 3.0
Терентьев М. 3.1
Хардин К. 4.0
Гончаренко С. 5.0
Требуется:
создать массив указателей на записи, содержащие сведения о студентах;
написать процедуру вывода информации о студентах на экран;
написать процедуру, определяющую студентов с наибольшей и наименьшей оценкой и меняющую их местами.
В приведенной ниже программе задачу 2 выполняет процедура Screen, задачу 3 – процедура Change.
Рассмотрим программу. В начале основной программы массив указателей GrpPtr заполняется значениями nil.
В результате выполнения цикла чтения данных из файла в основной программе формируется массив указателей GrpPtr на динамические переменные. Графически полученную структуру данных можно изобразить рисунком 4.1.
Рисунок 4.1 – До выполнения процедуры Change
В процедуре Change выявляются номер указателя на запись с наибольшим значением поля Ball (переменная imax) и номер указателя на запись с наименьшим значением поля Ball (переменная imin). Далее в указатель с номером imax записывается адрес, который хранился в указателе с номером imin. А в указатель с номером imin помещается адрес, ранее хранившийся в элементе массива с номером imax (см. рисунок 4.2).
Рисунок 4.2 – После выполнения процедуры Change
Вызов процедуры Screen по окончании работы процедуры Change выведет данные в виде:
Аношенко Г. 4.0
Гончаренко С. 5.0
Терентьев М. 3.1
Хардин К. 4.0
Ракаускайте К. 3.0
После окончания работы с динамическими переменными нужно освободить занятую ими память. Эту задачу выполняет последний фрагмент программы с помощью процедуры Dispose.
Текст программы имеет следующий вид.
program practic;
const NMAX=30;
type tStudent = record {запись}
Surname: String[20];
Ball : Real;
end;
pStudent = ^tStudent; {указатель на запись}
tGroup = array[1..NMAX] of pStudent; {массив указателей}
var GrpPtr: tGroup;
f: Text;
i: Integer;
fname: String[30];
{**************процедура вывода на экран**********************}
procedure Screen(var gr: tGroup);
var i: integer;
begin
writeln('*******gruppa*******');
i:=1;
while gr[i]<>nil do
begin
writeln(gr[i]^.Surname, gr[i]^.Ball:3:1);
i:=i+1;
end;
end;
{*************процедура обмена местами студентов ****************
*******************с высшим и низшим баллами*********}
procedure Change(var gr: tGroup);
var imax, imin, i: integer;
min, max : real;
ptmp : pStudent; {указатели}
begin
i := 1; imin := 1; imax := 1;
min := gr[1]^.Ball; max := gr[1]^.Ball;
{poisk max i min elementa}
while gr[i] <> nil do
begin
if gr[i]^.Ball > max then
begin
max := gr[i]^.Ball;
imax := i;
end;
if gr[i]^.Ball < min then
begin
min := gr[i]^.Ball;
imin := i;
end;
i:=i+1;
end;
{обмен указателей на данные с минимальным и максимальным значением поля Ball}
{меняем местами не сами записи a их адреса!}
ptmp := gr[imax];
gr[imax] := gr[imin];
gr[imin] := ptmp;
end;
{***************основная программа*****************}
begin
{заполняем массив указателей значениями nil}
for i:=1 to NMAX do
GrpPtr[i]:=nil;
{чтение данных из файла}
write('Enter file name ');
readln(fname);
assign(f,fname);
reset(f);
i:=1;
while not eof(f) do
begin
new(GrpPtr[i]); {выделяем память под новую динамическую переменную и помещаем ее адрес в i-ый элемент массива указателей}
with GrpPtr[i]^ do {помещаем данные в динамическую переменную}
readln(f,Surname, Ball);
i:=i+1;
end;
close(f);
{границу используемой части массива указателей теперь отмечает элемент,
содержащий значение nil}
Screen(GrpPtr); {Вывод данных на экран}
readln;
Change(GrpPtr); {Обмен}
Screen(GrpPtr); {Вывод данных на экран}
readln;
{удаление динамических переменных из памяти}
i:=1;
while GrpPtr[i]<>nil do
begin
dispose(GrpPtr[i]);
i:=i+1;
end;
end.
