Рейтинг@Mail.ru
Menu
Скачать картинки на телефон бесплатно.
Заставки для телефона, аватарки.
(Вырезать из фотографии)

Роза `Гренд Могул` Яхта `Алиса` Лесное озеро Музей `Пирогово` Белочка
Выберите рубрику (тему)

Тема: Указатели

Программа 11

  Длинный непрерывный текст представлен следующим образом: разделено на строки, каждый с є является массивом с n символов (или строкой длиной n). На каждую из таких строк ссылается элемент массива, общая размерность которого d, в порядке следования строк. Если строк меньш, чем d, то последние элементы содержат пустые посылки.
Описать процедуру, которая заменяет i-ю строку текста j-той строкой того же текста (копией j-й строки).

Текст программы

program Prg11;
{ http://nataliya.kiev.ua }
uses crt;
const d=50;
type el=^string;
   ar=array[1..50] of el;
   s=^ar;
var i,j:byte;
   a:s;
procedure newarray(d:byte; var a:s);
var n,i:byte;
begin
   new(a);
   n:=0;
   repeat
      inc(n);
      new(a^[n]);
      write('st',n,'=');
      readln(a^[n]^);
   until (a^[n]^='')or(n=d);
   for i:=n+1 to 50 do
      a^[i]:=nil;
end;
procedure main(d,i,j:byte;var a:s);
begin
   if a^[j]<>nil
   then begin
      if i<>j then
         if a^[i]<>nil then dispose(a^[i]);
      a^[i]:=a^[j];
      end
   else
      a^[i]^:='';
end;
procedure output(d,j:byte; const a:s);
var i:byte;
begin
   i:=0;
   repeat
      inc(i);
      if a^[i]<>nil then begin
         write('str',i,'=');
         writeln(a^[i]^)end
         else writeln('str',i,'=');
   until ((i>=j)and(a^[i]=nil)) or (i=d)
end;
begin
   clrscr;
   writeln('d=',d);
   newarray(d,a);
   Writeln('i<=',d,' j<=',d);
   repeat write('i='); readln(i) until i<=d;
   repeat write('j='); readln(j) until j<=d;
   main(d,i,j,a);
   output(d,i,a);
   Writeln('PRESS ANY KEY');
   readkey;
end.

Результат работы программы

1)
d=50
st1=1
st2=2
st3=3
st4=4
st5=5
st6=
i<=50 j<=50
i=2
j=1
str1=1
str2=1
str3=3
str4=4
str5=5
str6=
str7=
PRESS ANY KEY
2)
d=50
st1=modul
st2=crt
st3=pidtrymue
st4=robotu z viknamy
st5=yak
st6=z fragmentamy
st7=ekranu
st8=
i<=50 j<=50
i=2
j=15
str1=modul
str2=
str3=pidtrymue
str4=robotu z viknamy
str5=yak
str6=z fragmentamy
str7=ekranu
str8=
str9=
PRESS ANY KEY

Теория к программе

Указатели.
  Динамические структуры - структуры данных, размер которых (объем памяти, которую они занимают) может изменяться в процессе выполнения программы.
    Для организации таких структур используются динамические переменные, которые создаются и уничтожаются в процессе выполнения программы.
  Характеризуются:
    1. Эти переменные явным образом не описываются, к ним невозможно обратиться с помощью идентификатора.
    2. Память для этих переменных не выделяется во время формирования кода программы. Она выделяется в специальной области оперативной памяти - heap-области (динамической памяти) - только во время выполнения программы (откуда и название - динамические переменные).
    3. Доступ к таким переменным выполняется с помощью указателей (или ссылок), которые становятся активными после определения динамического объекта и содержат адрес в виде <сегмент>:<смещение>
Указатели могут содержать любой адрес: статических данных, фрагмента кода программы, стека и т.д.).
  Тип указатель
    Type <идентификатор>=^<базовый тип>;
<базовый тип> - определяет тип элементов, на которые будет указывать указатель
    Тип указатель - определяет множество значений дискретных переменных определенного типа, на которые может ссылаться соответствующий указатель.
    Описание базового типа не обязательно должно предшествовать описанию указателя, но должен содержаться в том же разделе описи типов.
  Обратиться к динамическим переменным можно только через указатель (а не через идентификатор):
      <указатель>^
  Встроенные средства
    • Существует зарезервированное константное значение, связанное с 'пустой ссылкой', которое имеет идентификатор:
      NIL ~ <#0>:<#0>
Этот указатель совместим с любым другим указателем (любого базового типа), т.е. переменной любого типа указателем может быть надано значение NIL.
    • Паскаль имеет встроенный тип указателя pointer
Это нетипизированный указатель (т.е., не связанный ни с одним базовым типом и вследствие этого совместим с любым типом указателя). Переменной типа pointer может быть представлено значение переменной любого типа указателя.
Но обращение к значению такой переменной (i^) может вызвать ошибку. Используется для описи формальных параметров типа указатель в процедурах и функциях.
    • Константа типа указатель может содержать только значение NIL
  Присваивание значения переменной-указателю
    • Присваивание указателю значение другого указателя.
    • С помощью специальной процедуры, которая связывает с динамической переменной область памяти в heap-области.
      NEW(var p:pointer);
  - создает новую динамическую переменную и устанавливает на нее указатель.
Фактический параметр - указатель любого типа. Размер выделяемого блока памяти отвечает размеру, нужному для размещения переменной базового типа (на который ссылается указатель).
Ссылка на созданную таким образом переменную - через соответствующий указатель. Если при выделении памяти для переменной не хватило места - возникает ошибка.
    • С помощью непосредственного предоставления указателю допустимого значения адреса:
    1) Использование оператора @
        @ - унарний оператор, который возвращает адрес статической переменной, процедуры или функции, совместимую с типом NIL (т.е. с любим типом указателя):
      a) использование для переменной - возвращает адрес этой переменной в виде <сегмент>:<смещение>
        @<идентификатор переменной> <указатель>
      b) использование для процедуры разрешает получить точку входа - адрес, из которого начинается ее выполнение. Используется для предоставления управления соответствующей процедуре или функции
        @<идентификатор процедуры, функции> <указатель на точку входа>
    2) addr(x):pointer;
      x - любая переменная или идентификатор процедуры/функции. Результат - указатель на x, совместимый со всеми типами указателей.
    3) ptr(<сегмент>,<смещение>:word):pointer;
      функция превращает предоставленный в виде <сегмент>:<смещение> адрес в указатель
    4) seg(x):word
      ofs(x):word
      x - идентификатор переменной, процедуры или функции. Эти функции возвращают:
        seg - адрес сегмента объекта x
        ofs - адрес смещения объекта x
    5) dseg:word; - функция возвращает адрес сегмента данных (содержимое регистра ds)
      cseg:word; - адрес сегмента кода (регистр cs)
      sseg:word; - адрес сегмента стека (регистр ss).
  Сравнение указателей(=, <>)
    Два указателя являются равными только в том случае, когда они ссылаются на тот самый объект - динамическую переменную. Использовать осторожно, поскольку не все процедуры нормализуют значение <сегмент>:<смещение>.
  Освобождение динамической переменной
    Присваивание указателю значение NIL разрывает связь между переменной и указателем, но не уничтожает самой переменной в динамической памяти. Место, которое она занимает, остается зарезервированным и не может быть использовано другими динамическими переменными.
      DISPOSE(var p:pointer);
      - процедура уничтожает динамическую переменную, на которую ссылается указатель p, и возвращает память, что она занимала, к динамической нераспределенной памяти. Значение указателя р становится неопределенным. Следить за освобождением динамических переменных следует самостоятельно.
  Образовывать и освобождать динамические переменные можно также с помощью другой пары процедур:
    getmem ~ freemem
  Но если в процедурах NEW - DISPOSE объем памяти, которая выделяется под динамическую переменную, определяется базовым типом указателя, то в процедурах getmem и freemem он определяется непосредственно, с помощью дополнительного параметра.
    getmem(var p:pointer;size:word);
      - образовывает динамическую переменную размером size
    freemem(var p:pointer,size:word);
      - освобождает динамическую переменную размером size.
  Параметр size должен равнять соответствующему параметру в процедуре getmem.
  Блочное освобождение памяти
    Существуют две связанные между собой процедуры, одна из которых фиксирует текущее состояние динамической памяти (например, перед вызовом блока процедуры или функции), а другая восстанавливает это состояние (например, после его выполнения, освобождая все динамические переменные, которые за это время были образованы).
      mark(var p:pointer);
    - записывает текущее состояние heap-области в переменную p (фактически записывается heaptr)
      release(var p:pointer);
    - возвращает динамическую область к предыдущему состоянию через указатель p (т.е. heapptr предоставляется значение p)
  Процедура release(heaporg); освобождает всю динамично распределенную память.
    Таким образом, существует несколько средств образования и уничтожение динамической переменной:
    1) NEW/DISPOSE
    2) NEW/MARK/RELEASE
    3) GETMEM/FREEMEM.
  Этими средствами не рекомендовано пользоваться одновременно (в одной программе).
  Структуры, построенные на базе указателей:
    1. Массивы указателей
    2. Линейные и циклические односвязанные списки, стек, очередь
    3. Линейные двухсвязные списки
    4. Деревья
  Массив указателей на данные одного типа. Элементами такого массива есть указатели на базовую структуру: строка, запись, и т.п.. Хотя сам массив имеет фиксированный размер и занимает постоянное место в оперативной памяти, динамические элементы базового типа будут образовываться и размещаться в динамической памяти во время выполнения программы.
  Линейный и циклический односвязанный список. Каждый отдельный элемент такой структуры содержит кроме одного или нескольких информационных полей поле, в котором сохраняется адрес следующего элемента. Последний элемент линейного списка содержит пустую ссылку (nil), тогда как последний элемент циклического списка содержит ссылку на первый элемент. Такие структуры образовываются и изменяются только во время работы программы.
  Стек типа FILO (first input last out) с помощью линейного односвязного списка может быть построенный следующим образом: список будет возрастать из конца, от элемента с пустой ссылкой на следующий. Каждый очередной элемент будет прибавляться перед ним и становиться текущим (доступным для обработки - чтения). При чтении последнего (текущего) элемента он уничтожается и указатель текущего элемента устанавливается на предыдущий.
  Очередь типа FIFO (first input first out) также может быть построена с помощью линейного односвязного списка. Добавление элемента к очереди будет выполняться в конец списка (после последнего элемента), а считывание - из первого элемента со следующим его уничтожением. Таким образом надо будет сохранить два указатели - ссылка на первый и последний элементы очереди.
  Двухсвязный список - такой, каждый элемент которого содержит две ссылки - на предыдущий и на следующий элементы. Первый элемент содержит пустую ссылку на предыдущий элемент, а последний - пустая ссылка на следующий элемент. Такой список также можно сделать циклическим.
  Существование двойной ссылки (на предыдущий и следующий элементы) предоставляет возможность двигаться по списку как в прямому так и в обратном направлениях, но немного усложняет процедуры изъятия и добавление элементов.
  Двоичные деревья могут также быть построены на базе элементов с двумя адресными полями. Одно из них содержит ссылку на левую, а второе - на правую ветвь поддерева, которое начинается с данного узла. Если одна из ветвей отсутствующая, в адресном поле, предназначенному для нее, содержится nil.

Случайный анекдот

Пожалуйста, не выгоняйте студентов из Гарварда. Дайте им доучиться. А то они потом Windows делают.
Дата: 05-05-2005   Автор: Admin   Подрубрика: Разное