Иллюстрированный самоучитель по Turbo Pascal

Использование указателей

Для рассматриваемого примера удобно резервировать фрагменты такой длины, чтобы в них могли, например, разместиться строки прямоугольной матрицы, т.е. 100 * 10 = 2000 байт. Начало каждого фрагмента, т.е. фактически начало размещения в памяти каждой строки, запоминается в массиве PTRSTR, состоящем из 100 указателей, теперь для доступа к любому элементу строки нужно вычислить смещение этого элемента от начала строки и сформировать соответствующий указатель:

var
i,j:Integer;
PtrStr: array [1..100] of pointer;
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);
if рr > 1 then
…….
end.

Поскольку оператор вычисления адреса PR: = PTR… будет, судя по всему, использоваться в программе неоднократно, полезно ввести вспомогательную функцию GETR, возвращающую значение элемента матрицы, и процедуру PUTR, устанавливающую новое значение элемента (правила объявления процедур и функций изложены в гл. 8). Каждая из них, в свою очередь, обращается к функции ADDRR для вычисления адреса. В примере 6.1 приводится программа, создающая в памяти матрицу из NxM случайных чисел и вычисляющая их среднее значение.

Пример 6.1.

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 {AddrR};
{-------------------}
Function GetR(i,j: Integer): Real;
{Выдает значение вещественной переменной по сегменту i и смещению j ее адреса}
begin
GetR: = AddrR(i,j)
end {GetR};
{-------------------}
Procepure PutR(i,j: Integer; x: Real);
{Помещает в переменную, адрес которой имеет сегмент i и смещение j, вещественное значение x}
begin
AddrR (i, j): = x
end {PutR};
{-------------------}
begin {Main}
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 * М):12:10)
end {Main}.

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

Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.