Указатели можно только присваивать и сравнивать на равенство и неравенство. При этом необходимо следить за согласованностью типов указателей: оператор p1:=p2 и сравнение p1=p2 правильные, а оператор p1:=p3 и сравнение p1=p3 будут считаться синтаксической ошибкой. Однако можно выполнить присваивание в два приема с использованием нетипизированного указателя p5, а именно: p5:=p3; p1:=p5. Аналогично можно сравнивать любой типизированный с нетипизированным указателем.
4.13.2. Использование указателей при вызове процедур.
Предположим, что формальный параметр z процедуры p является указателем на значение определенного типа (например, целого). Тогда при обращении к процедуре во внутреннюю переменную скопируется адрес, а само значение по данному адресу не будет затронуто. Если в процедуре встретится присваивание вида z^ := 7, то по адресу указателя заносится число 7. При выходе из процедуры это значение останется, то есть переменная по этому адресу получит новое значение. Например, после вызова p(@n) переменная n примет значение 7. Эффект будет таким же, как если бы задать параметр обычным целым числом, но описать его выходным (с ключевым словом var) и обратиться к процедуре оператором p(n).
Однако использование указателя имеет свои преимущества. Оно позволяет обойти стандартное ограничение Паскаля на строгое соответствие типов формального и фактического параметров вызова процедуры. Особенно это касается соответствия длин массивов. Дело в том, что определение указателя некоторого типа требует выделения памяти для хранения адреса, но не требует выделения памяти для хранения значения этого типа. Оператор вида p:=@x всего лишь совмещает значение, обозначаемое как p^, с уже существующей переменной x. Пусть имеется указатель p на массив некоторой длины n и массив a меньшей длины k, а типы элементов массивов одинаковые. Если теперь присвоить p^:=@a, то при обращении к элементам вида p^[m], где m>k, фактически произойдет обращение к памяти, не принадлежащей массиву a, что неправильно. Но если программно следить за тем, чтобы индекс в выражении p^[m] не превосходил фактической длины массива k, то программа будет действовать корректно. Поэтому можно составить процедуру, обрабатывающую массив максимально возможной длины, а при вызове процедуры передавать ей указатель на начало фактического массива и длину фактического массива. В качестве примера приведем функцию поиска целого значения в массиве произвольной длины.
function find_integer (
x: integer; {Значение для поска}
p: pointer; {Массив для поиска}
n: integer) {Длина массива}
: integer; {Возвращает номер совпавшего элемента или 0 в случае неудачи}
type ar: array [1..30000] of integer;
var
k: integer;
p1: ^ar;
begin
find_integer := 0;
p1 := p;
for ki:=1 to n do
if p1^[k]=x then
begin
find_integer := k;
break
end
end;
Обратиться к данной функции можно следующим образом:
var a: array [1..20] of integer;
…
i := find_integer (23,@a,20);
4.13.3. Использование указателей для обработки списков.
Указатели оказываются незаменимыми в задачах, связанных с добавлением и корректировкой данных в структурно организованных системах данных. Дело в том, что хранение данных в массивах наталкивается на серьезные технические трудности. Добавление данных возможно только вконец массива. Если играет роль порядок данных, то при вставке элемента в середину массива необходимо сдвинуть все остальные элементы. Это очень неудобно или даже невозможно, если номера данных по одному массиву используются в других массивах.
8th Май 2011
|
Теги:
|