Примеры использования указателей
Пример: создать в динамической памяти массив из переменных вещественного типа размерностью 100 * 200.
Для решения данной задачи воспользуемся следующими функциями:
Seg(x) – возвращает сегментную часть адреса;
Ofs(x) – возвращает смещение.
(Тип обоих функций – word).
Аргументом xпри обращении к этим функциям может служить любая переменная, в том числе и та, на которую указывает указатель.
С помощью встроенной функции
Ptr (seg, ofs: word): pointer
можно создать значение указателя совместимое с указателями любого типа.
Для рассматриваемого примера удобно резервировать фрагменты такой длины, чтобы в них могли, например, разместиться строки прямоугольной матрицы, т.е. 200 * 6 = 1200 байт. Начало каждого фрагмента, т.е. фактически начало размещения в памяти каждой строки, запоминается в массиве PtrStr, состоящем из 100 указателей. Теперь для доступа к любому элементу строки нужно вычислить смещение этого элемента от начала строки и сформировать соответствующий указатель:
Var
i, j: integer;
PtrStr : array [1..100] of pointer;
pr : ^real;
Const
SizeOfReal = 6;
Begin
for i := 1 to 100 do
GetMem (PtrStr[i], SizeOfReal * 200);
…
{Обращение к элементу матрицы [i,j]}
pr := Ptr(Seg (PtrStr[i]^), Ofs (PtrStr[i]^) + (j – 1) * SizeOfReal);
…
End.
Пример: создать в памяти матрицу размерностью N * M, заполнить ее случайными числами и вычислить среднее значение.
const
SizeOfReal = 6; {Длина переменной типа REAL}
N = 100; {Количество столбцов}
М = 200; {Количество строк}
var
i, j: integer;
PtrStr: array [1..N] of pointer;
s : real;
type
RealPoint = ^real;
function AddrR (i, j : word): RealPoint;
{Функция по сегменту i и смещению j выдает адрес вещественной переменной}
begin
AddrR := Ptr (Seg (PtrStr[i]^), Ofs (PtrStr[i]^)+(j –1)* SizeOfReal);
End;
function GetR (i, j: integer): real;
{Функция выдает значение вещественной переменной по сегменту i смещению j ее адреса}
begin
GetR := AddrR (i, j)^;
End;
procedure PutR (i, j : integer; x: real);
{Процедура помещает в переменную, адрес которой имеет сегмент i смещение j, вещественное значение х}
begin
AddrR (i, j)^ := x;
end;
{Основная программа}
begin
for i :=1 to N do
begin
GetMem (PtrStr[i], M * SizeOfReal);
for j := 1 to M do
PutR (i, j, Random)
end;
s := 0;
for i := 1 to N do
for j := 1 to M do
s := s + GetR(i,j);
WriteLn (s / (N * M) : 12:10)
end.
Динамические списковые структуры
На практике часто указатели используются, чтобы связать записи друг с другом. Для этого применяют следующую конструкцию:
Type
link = ^zap;
dan =…;
zap = record;
pole1: link;
pole2: dan;
end;
Var
p: link;
link – это указатель на область памяти для записи переменных типа zap.
Тип zap оказывается записью, где имеются поля, содержащие информацию (типа dan) и одно поле pole1 типа link, т.е. указатель. Указатель указывает на следующую запись того же самого типа.
Переменная p есть указатель на область памяти, где можно хранить запись. С помощью оператора New(pul) резервируется область памяти для хранения записи и одно из полей этой записи может содержать указатель, который в свою очередь мог указывать на другую запись.
Образуется последовательность следующего вида (рис. 5):
Рис. 5. Последовательность записей в динамическом списке
Для заполнения полей можно использовать операторы присваивания:
pul^.имя поля := значение;
Пример.Программа создает пять записей для хранения целых чисел. Записи указывают одна на другую. Затем записи выводятся в порядке, обратном порядку создания записей. Первая сформированная запись в списке будет последней.
Type
link = ^zap;
zap = record;
pole1: link;
pole2:integer;
end;
Var
z, p: link;
Begin
{Запись чисел}
z:=nil;
for k:=1 to 5 do
Begin
new(p);
p^.pole2:=k;
p^.pole1:=z;
z:=p;
end;
{Считывание в обратном порядке}
for k:=1 to 5 do
Begin
WriteLn(p^.pole2);
p:=p^.pole1;
end;
End.
Считывание чисел также можно осуществить следующим образом:
while p<>nil do
Begin
WriteLn(p^.pole2);
p:=p^.pole1;
end;
Пример. Построить список, элементы которого содержат квадраты чисел 1,2, …, n.
Type
cc=^zap;
zap = record;
pl1: integer;
pl2: cc;
end;
Var
p,q: cc;
i,n: integer;
Begin
WriteLn(‘введите n’);
ReadLn(n);
p:=nil;
for i:=n downto 1 do
Begin
New(q);
q^.pl1:=sqr(i);
q^.pl2:=p;
p:=q;
End;
q:=p;
while q<>nil do
Begin
Write(q^.pl1);
q:=q^.pl2;
End;
Dispose(p);
Dispose(q); }
End.
Пример. Построить список, состоящий из нечетного количества целых чисел. Вывести число, занимающее в данной последовательности центральную позицию.
Type
ck=^tip;
tip=record
inf: integer;
cled: ck;
end;
Var
p,q: ck;
i,j: integer;
Begin
p:=nil;
WriteLn(‘Введите нечетное количество целых чисел’, j);
for i:=1 to j do
Begin
New(q);
Read(q^.inf);
q^.cled:=p;
p=q;
end;
for i:=1 to j div 2 do
q:=q^.cled;
WriteLn(q^.inf);
End.
Пример. Построить список, состоящий из записей, содержащих сведения о студенте: ФИО, экзаменационные оценки по физике, математике и программированию.
Вывести список на экран в виде таблицы и подсчитать средний балл.
uses Crt;
Type
pst=^st;
st=record
fio: string[20];
math: integer;
phys: integer;
prog: integer;
pt: pst;
end;
Var
q, p: pst;
i, j, n: integer;
d: real;
Begin
ClrScr;
Write(‘Введите число записей’);
ReadLn(n);
p:=nil;
for i:=1 to n do
Begin
New(q);
WriteLn(‘Введите ФИО’);
ReadLn(q^.fio);
WriteLn(‘Введите оценку по математике’);
ReadLn(q^.math);
WriteLn(‘Введите оценку по физике’);
ReadLn(q^.phys);
WriteLn(‘Введите оценку по программированию’);
ReadLn(q^.prog);
q^.pt:=p;
p:=q;
end;
q:=p;
WriteLn;
for j:=1 to 56 do
Write(‘-‘);
WriteLn;
WriteLn(‘| fio stud | math | phys | prog | sr. ball |’);
for j:=1 to 56 do
Write('-');
WriteLn;
for i:=1 to n do
Begin
d:=(q^.math + q^.phys + q^.prog)/3;
WriteLn(‘| ‘, q^.fio:20, ‘ | ‘, q^.math:4, ‘ | ‘,q^.phys:4, ‘ |
‘,q^.prog:4, ‘ | ‘, d:8:2,’ |’);
q:=q^.pt;
end;
for j:=1 to 56 do
Write(‘-‘);
WriteLn;
Dispose(p);
Dispose(q);
ReadLn;
End.
Альтернативный вариант предыдущей программы, но список выводится в правильном порядке.
uses Crt;
Type
pst=^st;
st=record
fio: string[20];
math: integer;
phys: integer;
prog: integer;
pt: pst;
End;
Var
nach, q, p : pst;
i ,j ,n : integer;
d : real;
Begin
ClrScr;
Write(‘Введите число записей’);
ReadLn(n);
New(q);
for i:=1 to n do
Begin
q^.pt:=nil;
if i = 1 then nach:=q;
WriteLn(‘Введите ФИО’);
ReadLn(q^.fio);
WriteLn(‘Введите оценку по математике’);
ReadLn(q^.math);
WriteLn(‘Введите оценку по физике’);
ReadLn(q^.phys);
WriteLn(‘Введите оценку по программированию’);
ReadLn(q^.prog);
p:=q;
New(q);
if i<>n then p^.pt:=q
Else
Dispose(q);
end;
WriteLn;
for j:=1 to 56 do
Write(‘-‘);
WriteLn;
WriteLn(‘| fio stud | math | phys | prog | sr. ball |’);
for j:=1 to 56 do
Write(‘-‘);
WriteLn;
q:=nach;
while q<>nil do
Begin
d := (q^.math + q^.phys + q^.prog)/3;
WriteLn(‘| ‘, q^.fio:20, ‘ | ‘, q^.math:4, ‘ | ‘,q^.phys:4,
‘ | ‘,q^.prog:4, ‘ | ‘, d:8:2,’ |’);
q:=q^.pt;
end;
for j:=1 to 56 do
Write(‘-‘);
WriteLn;
Dispose(p);
Dispose(q);
ReadLn;
end.
Дата добавления: 2017-01-29; просмотров: 727;