Файл: Лабораторная работа 1 Динамические структуры данных.docx
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 12.12.2023
Просмотров: 99
Скачиваний: 3
| Объявление var pc: ^char; // адрес символа pi : ^integer; // адрес целой переменной |
| var p: pointer; |
| begin var i := 3; var p := @i; // автовыведение типа ^integer Writeln(p); // $23ED24 - как пример end. |
| Как записать адрес: var m: integer; // целая переменная pi : ^integer; // указатель A: array[1..3] of integer begin pi:= @m; // адрес переменной m pi = @A[1];//адрес элемента массива A[1] pi := nil; // нулевой адрес (указатель не указывает никуда) |
Смысл использованию указателей придает операция разыменования, позволяющая обращаться к содержимому памяти по адресу, который хранится в типизированном указателе. Операция разыменования использует тот же знак, что и описание типизированного указателя, только записывается он после имени указателя. Разыменовываемый указатель может появиться и в левой части оператора присваивания.
| begin var i := 3; var p := @i; // автовыведение типа ^integer p^ := p^ * 2 + 1; Writeln(i); // теперь i = 7 end. |
| var n,m:integer; pInt: ^integer; A: array[1..3] of integer; begin n := 4; pInt:= @n;// в область памяти pInt помещаем n writeln('Адрес n =',pInt); // вывод адреса памяти writeln('n = ', pInt^); // вывод значения по адресу m := 4*(7-pInt^); pInt^ := 4*(m-n); writeln('n = ', pInt^); writeln('n = ', m); end. |
| type УказательНаУзел = ^Узел; Узел = record Значение: integer; Связь: УказательНаУзел end; |
| var p: ^integer; q : ^Byte p := q; {p : ^Integer; q : ^Byte} |
| {p : ^Integer; q : ^Byte; t : Pointer} t := q; p := t; |
Динамическое распределение памятиПоскольку к любой переменной можно обратиться двояко — по имени и по адресу, — есть возможность сократить эту избыточность и оставить только один способ. Как мы уже видели, наличие имени означает и наличие адреса. Иными словами, если вы дали переменной имя в разделе var, то в процессе компиляции у неё появится и адрес.Задумаемся теперь: а если у переменной есть адрес, но нет имени, можно ли оперировать ею с прежней легкостью? Ответ на этот вопрос: «Да, можно!»Итак, пусть у некоторой переменной нет имени. Тем не менее, можно расположить её в памяти, выделив под неё необходимое количество байтов, и т.д. У переменной будет адрес, будет значение, но не будет имени. Следовательно, обратиться к такой переменной можно будет только с помощью указателя.«Безымянные» переменные отличаются от «нормальных» переменных:1. Нет имени — нечего описывать в разделе var.2. Ничего не описано, значит, на этапе компиляции память под переменную не выделена. Следовательно, необходима возможность выделять память (и отменять это выделение) прямо в процессе работы программы. Именно из–за этой гибкости такие переменные и называют динамическими.3. Если «потерять» указатель на переменную, то «никто не узнает, где могилка» её: переменная останется недоступным «мусором», занимая место в памяти, вплоть до конца работы программы. (Проблема утечки памяти!).Динамическое выделение памяти– Типизированные указатели:Для выделения памяти служит стандартная процедура New():Эта процедура ищет в незанятой памяти подходящий по размеру кусок и, «застолбив» это место для безымянной динамической переменной, записывает в типизированный указатель адрес выделенного участка. Поэтому часто говорят, что процедура New() создаёт динамическую переменную. Размер выделяемого «куска памяти» напрямую зависит от типа указателя.Например, если переменная p была описана как указатель на Integer–переменную, то процедура New(p) выделит два байта; под Real–переменную необходимо выделить шесть байт и т. д.– Нетипизированные указатели:Для того, чтобы выделить память, на которую будет указывать нетипизрованный указатель Pointer, нужно воспользоваться стандартной процедурой GetMem(p : Pointer; size : Word), которая
выделит столько байт свободной памяти, сколько указано в переменной size.
Список. Создание списка путем добавления элементов в конец списка. Просмотр списка
Определение. Списком называется структура данных, каждый элемент которой посредством указателя связывается со следующим элементом.
Из определения следует, что каждый элемент списка содержит поле данных (Data) (оно может иметь сложную структуру) и поле ссылки на следующий элемент (Next). Поле ссылки последнего элемента должно содержать пустой указатель (Nil).
Схематически это выглядит так:
Рис. 1 Структура данных типа список
Задача. Сформировать список, содержащий целые числа 3, 5, 1, 9.
Для этого сначала определим запись типа S с двумя полями. В одном поле будут содержаться некоторые данные (в нашем случае числа 3, 5, 1 и 9), а в другом поле будет находиться адрес следующего за ним элемента.
| Type Ukazatel = ^S; S = Record Data : integer; Next : Ukazatel ; End; |
| Var Head, {указатель на начало списка}x {вспомогательный указатель для создания очередного элемента списка}: Ukazatel; |
| New(x); {выделим место в памяти для переменной типа S} x^.Data := 3; {заполним поле Data первого элемента} x^.Next := Nil; {заполним поле Next первого элемента: указатель в Nil} Head := x; {установим указатель головы списка на первый элемент} |
Таким образом, к выделенной области памяти можно обратиться через два указателя.Продолжим формирование списка, для этого добавим элемент в конец списка. Вспомогательная переменная указательного типа х будет хранить адрес последнего элемента списка. Сейчас последний элемент списка совпадает с его началом, поэтому справедливы равенства:
| Head^.Next = x^.Next; Head^.Data = x^.Data; Head = x; |
| New(x^.Next); |
| x := x^.Next; |
| x^.Data := 5; x^.Next := Nil; |
| Procedure Init(Var u : Ukazatel); Var x : Ukazatel; Digit : integer; {Значение информационной части элемента списка} Begin Writeln('Введите список '); u := Nil; {Список пуст} Writeln ('Введите элементы списка. Конец ввода 0'); Read (Digit); if Digit <> 0 then {Формируем и вставляем первый элемент списка} Begin New(x); x^.Next := Nil; x^.Data := Digit; u := x; Read (Digit); while Digit<>0 do Begin New(x^.Next); {Формируем и вставляем элемент в конец списка} x := x^.Next; x^.Next := Nil; x^.Data := Digit; Read(Digit); End; End; Writeln; End; |