Pascaler
О проекте Теоретический материал Тестирование Архив задач
Войти в личный кабинет



О проекте


Преподавателям


Тема: Присвоение значений указателю. Оператор @ с переменной. Оператор @ с параметром процедуры, переданным по значению. Оператор @ с параметром процедуры, переданным по ссылке.

Переменной-указателю можно присвоисть значение другого указателя того же типа. В языке существует универсальный тип указателя, его имя - pointer. Используя тип pointer как промежуточный, можно присвоить значение одного указателя другому и при несовпадении их типов.

Для инициализации указателей в Паскале предусмотрены специальные процедуры и функции.

Переменной-указателю можно присвоить значение с помощью процедуры new, операции @ или функции Ptr.

Процедура new отводит блок памяти в области для динамических переменных и сохраняет адрес этого блока в указателе.

Операция @ ориентирует переменную-указатель на область памяти, содержащую уже существующую переменную. Ее можно применять к статическим переменным, динамическим переменным, процедурам и функциям.

Функция Ptr ориетирует переменную-указатель на определенный адрес в памяти. Тип результата - указатель того же типа, что и Nil, т.е. он может быть назначен любой переменной-указателю.

@ - это унарный оператор. Тип значения указателя управляется через директуву компилятора $T. Если переключателшь отключен, то результатом является нетипизированный указатель, если включен, - то тип указателя соответствует типу объекта. Если оператор @ применяется к процедуре, функции или методу, то результатом всегда будет указатель типа pointer, независимо от состояния опции $T.

Оператор @ с переменной

Использование @ с обычной переменной (не параметром процедуры) несложно.

Например, можно задать декларацию

Type
  A = Array [0..99] of char; {Тип массива символов}
Var
  X : Array [0..49] of integer; {Массив целых чисел}
  pA : ^A; {Указатель на массив символов}

Объявлены переменные двух разных типов: массива целых из 50 элементов и ссылочного на тип А (массив из 100 символов). Чтобы указатель рА указывал на массив Х, надо присвоить ему адрес Х:

рА := @Х; {Указатель на массив целых чисел}

Теперь pA^ ссылается на массив целых, но по своей природе он указатель на массив символов, поэтому при обращении pA^[i] мы получаем содержимое отдельных байтов массива Х в символьной форме.

Пример. Компонентам массива целых присваиваются сдвинутые на 65 значения индекса, печатается массив целых. Переменной-указателю на символьный массив присваивается адрес массива целых. Снова распечатывается массив, но по адресам значений. Вместо последовательности чисел будет напечатана последовательность ASCII символов от А до z с пробелами.

Program ReInterpretation;
{Интерпретация массива целых чисел как массива из символов}
Uses
  Crt;
Type
  A = Array [0..99] of char; {Тип A - массив 100 символов}
Var
  X : Array [0..49] of integer; {Массив целых чисел}
  pA : ^A; {Указатель на массив символов}
  i : integer;
Begin
  ClrScr;
  for i := 0 to 49 do
    begin
      X[i] := 65+i {65 - код буквы А}
      write(X[i], ' '); {Печать чисел}
    End;
  pA := @X; {Указателю на А присваивается адрес массива целых чисел}
  writeln;
  for i := 0 to 99 do
    write(pA^[i],' '); {Печать символов}
End.

Попытка исполнить последний оператор до оператора pA := @X привела бы к ошибке, поскольку указатель на массив был бы не опpеделен. Массив Х имеет значения 65..114, которые не выходят за пределы младшего байта двухбайтовых элементов типа word. В старших байтах этой переменной - нули. При побайтной печати массива младшие байты выводятся как буквы алфавита, а старшие - как символ #0, который процедурой write интерпретируется как пробел.

Задание. Наберите программу, откомпилируйте ее и проверьте действие.

Оператор @ с параметром процедуры, переданным по значению

Применение @ к формальному параметру процедуры означает то же, что ссылка на фактический параметр, находящийся в стеке.

Например, пусть Х - формальный параметр процедуры, а рХ - указатель на него. Если в процедуре выполнено назначение

рХ := @Х;

то рХ^ указывает на значение Х, которое хранится в стеке.

Пример. Процедура Test присваивает локальному параметру р его адрес и выводит значение адреса в формате сегмент : смещение . Основная программа обращается к процедуре с фактическим параметром Р и выводит адрес фактического параметра.

Program FormalParam;
{Определение адреса формального параметра}
Uses
  Crt;
Var
  P : pointer;
Procedure Test(p: pointer);
Begin
  p := @P; {Определение адреса локального параметра}
  writeln ('', Seg(p^), ':', Ofs(p^));
End;
Begin
  ClrScr;
  Test(P); {Вызов процедуры}
  writeln('', Seg(p^), ':', Ofs(p^));
End.

На экран будет выведен результат исполнения программы:

В процедуре Р=1103:16378

В основной программе Р=0:0

Задание. Наберите программу, откомпилируйте ее и проверьте действие.

Оператор @ с параметром процедуры, переданным по ссылке

Применение оператора @ к формальному переменному параметру процедуры приводит к указанию на действительный параметр процедуры (указатель берется из стека).

Например, пусть

Х - формальный переменный параметр процедуры;

а - переменная, передаваемая в процедуру как действительный параметр;

рХ - ссылочная переменная.

Если процедура, как в предыдущем примере, выполняет присвоение

pХ := @X;

то pХ - указатель на а, а pX^ - ссылка на само значение а.

Задание. Чтобы проверить выше сказанное, модифицируйте в предыдущем примере единственную строчку, передав указатель в процедуру по ссылке:

Procedure Test(Var p:pointer);

Значение указателя в основной программе изменится и будет равно значению указателя в подпрограмме. Результат:

В процедуре Р=1119:98

В основной программе Р=1119:98

Задание. Используя одну из созданных Вами программ в теме "Процедуры и функции", модифицируйте ее, применив знания этого занятия.

Вернуться назад
2003—2012 © Группа «Vimedia»
Проект «Pascaler» — лучший на ХI Всероссийской конференции молодых исследователей с международным участием «Шаг в будущее», Россия, Москва, 12 – 16 апреля 2004г.