Работа с данными неизвестного размера 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Работа с данными неизвестного размера



Некоторые элементы данных Turbo Pascal (в частности, строки и массивы) требуют задания размеров во время компиляции, даже если при выполнении программы вам не потребуется вся выделенная память. Простым примером может быть программа, считывающая вводимую пользователем строку, например, имя пользователь. Чтобы записать имя в обычной строковой переменной, вам потребовалось бы зарезервировать достаточно памяти для максимальной возможной строки, даже если набранное имя содержит всего несколько букв. Если вы распределяете переменные в динамически распределяемой области памяти во время выполнения, то можете выделить точно столько байт, сколько необходимо для фактической строки данных.

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

Работа с временными буферами данных

Указатели и динамически распределяемая область памяти особенно полезны в тех случаях, когда вам требуется временное выделение памяти, и вы не хотите удерживать ее на все время выполнения программы. Например, редактору файлов обычно требуется буфер данных для каждого редактируемого файла. Вместо описания на этапе компиляции, что вам необходимо определенное число буфером заданного размера, которые всегда распределяются для файлов, вы можете выделить их столько, сколько необходимо в каждый конкретный момент, что делает память доступной для других целей.

Другим общим примером использования временной памяти является сортировка. Обычно когда вы сортируете большой объем данных, то делаете копию массива, сортируете копию, а затем записываете отсортированные данные обратно в исходный массив. Это сохраняет целостность ваших данных, но требует также наличия во время сортировки двух копий данных. Если вы хотите распределить сортируемый массив в динамически распределяемой памяти, то можете отсортировать его и скопировать обратно в оригинал, а затем уничтожить сортируемый массив, освободив память для других нужд.

Работа с несколькими типами данных

Одной из общих причин использования указателей является ссылка на переменные структуры данных, то есть записи или массивы, которые не всегда имеют одну и ту же структуру. Например, вы можете выделить блок памяти, зарезервированный для "протокола" элементов строк различной длины, набранных в поле ввода данных. Чтобы прочитать список протокола, подпрограмма должна просмотреть блок и найти отдельные строки. Для указания начала блока вы можете использовать простой указатель. В этом случае указатель работает аналогично передаче функции или процедуре нетипизированного параметра var - вы просто хотите сообщить, где что-то находится, без указания того, что это такое.

Примечание: О нетипизированных параметрах-переменных рассказывается в Главе?? ("Процедуры и функции").

Связанные списки

Одним из общих случаев использования указателей является соединение связанных списков записи. Во многих простых приложениях типа баз данных вы можете размещать записи данных в массивах или типизированных файлах, но иногда требуется что-то более гибкое, чем массив, который имеет фиксированный размер. Распределяя динамические записи, так что каждая запись имеет поле, указывающее на следующую запись, вы можете построить список, содержащий столько элементов, сколько вам требуется.

Что такое указатель?

Указатель - это какой-либо адрес в памяти вашего компьютера. Это может быть адрес переменной, записи данных, либо процедуры или функции. Обычно вам не важно, где расположен элемент в памяти. Вы можете просто ссылаться на него по имени, и Turbo Pascal знает, где его нужно искать.

Именно это происходит, когда вы описываете переменную. Например, если программа включает в себя следующий код, то вы указываете компилятору на необходимость зарезервировать область в памяти, на которую будете ссылаться по имени SomeNumber.

 

var SomeNumber: Integer;

 

Вам не нужно беспокоиться о том, где SomeNumber находится в памяти. Именно для этого задается имя.

Адрес размещения SomeNumber в памяти можно найти с помощью операции @. @SomeNumber - это адрес вашей целочисленной переменной. Вы можете присвоить этот адрес переменной-указателю, то есть переменной, содержащей адрес данных или кода в памяти.

Ссылочный тип

Чтобы хранить указатели, вам требуется переменная-указатель, а для создания переменной-указателя вам необходим ссылочный тип (или тип "указатель"). Простейшим ссылочным типом является стандартный тип с именем Pointer. Переменная типа Pointer - это общий (нетипизированный) указатель, то есть, просто адрес. Он не содержит информации о том, на что он указывает.

Таким образом, чтобы использовать тот же пример SomeNumber, вы можете присвоить его адрес переменной-указателю:

 

var

SomeNumber: Integer;

SomeAddress: Pointer;

begin

SomeNumber:= 17; {присвоить SomeNumber значение}

SomeAddress:= @SomeNumber; {присвоить SomeAddress адрес}

SomeAddress:= Addr(SomeNumber); {другой способ получения

адреса}

end.

 

Нетипизированные указатели в Паскале не используются, поскольку они очень ограничены. Они наиболее полезны, когда указываемый элемент будет изменяться, так как нетипизированный указатель совместим с любым другим указателем. Типизированные указатели значительно более полезны, и как вы узнаете в следующем разделе, они более надежны.

Типизированные указатели

Обычно вы определяете ссылочные типы, которые указывают на конкретный вид элемента, например, целое значение или запись данных. Как вы далее увидите, можно извлечь преимущество из того факта, что указателю известно, на что он указывает. Чтобы определить типизированный указатель, вы можете описать новый тип, определенный символом каре (^), за которым следуют один или более идентификаторов. Например, чтобы определить указатель на Integer, вы можете сделать следующее:

 

type PIneger = ^Integer;

 

Теперь вы можете описать переменные типа PInteger. Если вы не собираетесь часто использовать ссылочный тип, то можете просто описать переменные, как указатели на уже определенный тип. Например, если вы определили PInteger как ^Integer, то следующие описания переменной эквивалентны:

 

var

X: ^Integer:

Y: PInteger;

 

Разыменование указателей

До сих пор мы видели, как можно присваивать указателям значения, но если вы не можете получить значения обратно, польза от этого невелика. Разыменовав типизированный указатель, вы можете интерпретировать так, как если бы это была переменная типа, на которую он указывает. Чтобы разыменовать указатель, поместите символ каре (^) после идентификатора указателя.

Ниже показаны некоторые примеры разыменования указателя:

 

type PInteger = ^Integer;

 

var

SomeNumber: Integer; { присвоить SomeNumber 17 }

SomeAddress:= @SomeNumber; { SomeAddress указывает на SomeNumber }

Writeln(SomeNumber); { напечатать 17 }

Writeln(SomeAddress); { не допускается; указатели печатать нельзя }

Writeln(SomeAddress^); { напечатать 17 }

AnotherAddress:= SomeAddress; { также указывает на SomeNumber }

AnotehrAddress^:= 99; { новое значение для SomeNumber }

Writeln(SomeNumber); { напечатать 99 }

end.

 

Наиболее важными строками здесь являются следующие:

 

AnotherAddress:= SomeAddress; { также указывает на SomeNumber }

AnotehrAddress^:= 99; { новое значение для SomeNumber }

 

Как использовать указатели?

Теперь вы получили достаточно хорошее представление о том, в каких ситуациях вы можете использовать указатели, и можно рассмотреть их фактическое применение. В данном разделе охватываются следующие темы:

- Распределение динамических переменных.

- Освобождение выделенной для динамических переменных памяти.

- Распределение и освобождение выделенных объемов памяти.

- Проверка доступного в динамически распределяемой области пространства.

Turbo Pascal предусматривает две пары процедур для выделения и освобождения памяти, распределяемой для динамических переменных. Чаще всего используются процедуры New и Dispose, которые отвечают большинству потребностей. Процедуры GetMem и FreeMem выполняют те же функции, но на более низком уровне.



Поделиться:


Последнее изменение этой страницы: 2017-02-19; просмотров: 257; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.22.70.9 (0.014 с.)