Студопедия
Случайная страница | ТОМ-1 | ТОМ-2 | ТОМ-3
АрхитектураБиологияГеографияДругоеИностранные языки
ИнформатикаИсторияКультураЛитератураМатематика
МедицинаМеханикаОбразованиеОхрана трудаПедагогика
ПолитикаПравоПрограммированиеПсихологияРелигия
СоциологияСпортСтроительствоФизикаФилософия
ФинансыХимияЭкологияЭкономикаЭлектроника

Руководство пользователя 18 страница



режима командной строки.

 

Если вы поместите свой модуль в заданный каталог модулей, то

сможете ссылаться на этот модуль, даже если он не находится в те-

кущем каталоге или в библиотеках исполняющей системы.

 

Включите в любую программу, где вы хотите использовать свой

новый модуль, оператор uses. Например, если ваш новый модуль на-

зывается INTLIB.TPW, то задайте в своей программе оператор следу-

ющего вида:

 

uses IntLib;

 

Чтобы найти модуль, имя которого указано в операторе uses,

Borland Pascal проверяет его наличие в библиотеке исполняющей

системы, загруженной в память в время инициализации.

 

Примечание: О том, как поместить модуль в библиотеку

исполняющей системы, рассказывается ниже.

 

Если модуль в библиотеке исполняющей системы отсутствует, то

компилятор ищет его на диске, сначала в текущем каталоге, затем в

каталогах, заданных в качестве каталогов модулей (Options│

Directories). Компилятор предполагает, что имя файла совпадает с

именем модуля, а расширение имени файла - это.TPU,.TPW или

.TPP. Исходный текст модуля имеет расширение.PAS.

 


 

B.Pascal 7 & Objects /UG - 173 -

 

Пример

 

Теперь напишем небольшой модуль. Назовем его IntLib и вста-

вим в него две простые подпрограммы для целых чисел - процедуру и

функцию:

 

unit IntLib;

 

interface

procedure ISwap(var I,J: integer);

function IMax(I,J: integer): integer;

implementation

procedure ISwap;

var

Temp: integer;

 

begin

Temp:= I; I:= J; J:= Temp

end; { конец процедуры ISwap }

function IMax;

begin

if I > J

then IMax:= I

else IMax:= J

end; { конец функции IMax }

end. { конец модуля IntLib }

 

Наберите этот модуль, запишите его в файл INTLIВ.PAS, а за-

тем скомпилируйте, задав в качестве целевой платформы защищенный

режим DOS. В результате получим код модуля в файле INTLIВ.ТРP.

Перешлем его в каталог модулей (если такой имеется), или оставив

в том же каталоге, где находится следующая программа, которая ис-

пользует модуль IntLib:

 

program IntTest;

uses IntLib;

var

A,B: integer;

begin

Write('Введите два целочисленных значения: ');

Readln(A,B);

ISwap(A,B);

Writeln('A = ',A,' B = ',B);

Writeln('Максимальное значение равно ',IMax(A,B));

end. { конец программы IntTest }

 

 

Модули и большие программы

 

До сих пор мы говорили о модулях как о библиотеках - наборах


 

B.Pascal 7 & Objects /UG - 174 -

 

полезных подпрограмм, которые могут использоваться несколькими

программами. Однако, у модуля есть еще одна функция - разбивать

большую программу на составные части.

 

Два аспекта Borland Pascal способствуют использованию моду-



лей в такой функции:

 

* высокая скорость компиляции и компоновки;

 

* способность работать с несколькими файлами одновременно,

например, с программой и несколькими модулями.

 

Обычно большая программа разбивается на модули, которые

группируют процедуры по их функциям. Например, программа редакто-

ра может быть разделена на части, выполняющие инициализацию, рас-

печатку, чтение и запись файлов, форматирование и так далее. Так-

же, как имеется основная программа, определяющая глобальные конс-

танты, типы данных, переменные, процедуры и функции, так же может

иметь место и "глобальный" модуль, который используется всеми

другими модулями.

 

Набросок большой программы-редактора может иметь вид:

 

program Editor;

uses

WinCrt, String { стандартные модули из TPW.TPL }

EditGlobals, { модули, написанные пользователем }

EditInuit,

EditPrint,

EditRead, EditWrite,

EditFormat;

 

{ описание, процедуры и функции программы }

begin { основная программа }

end. { конец программы Editor }

 

Модули в данной программе могут содержаться в TPW.TPL, биб-

лиотеке исполняющей системы Windows, или быть отдельными файлами

.TPW. В последнем случае Borland Pascal выполняет за вас управле-

ние проектом. Это означает, что при перекомпиляции программы

Editor с помощью встроенного в компилятор средства формирования

Borland Pascal сравнивает даты каждого файла.PAS и.TPW и пере-

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

 

Другая причина использования модулей в больших программах

состоит в ограничения кодового сегмента. Процессоры 8086 (и родс-

твенные им) ограничивают размер сегмента кода 64 килобайтами. Это

означает, что основная программа и любой данный сегмент на может

превышать 64К. Borland Pascal интерпретирует это, создавая для

каждого модуля отдельный сегмент кода. Без этого объем кода вашей

программы не мог бы превышать 64К.

 


 

B.Pascal 7 & Objects /UG - 175 -

 

Примечание: Подробнее о работе с большими программными

проектами рассказывается в Главе 4 "Программирование в ин-

тегрированной среде для DOS".

 

 

Утилита TPUMOVER

─────────────────────────────────────────────────────────────────

 

Допустим, вы хотите добавить стандартным модулям хорошо на-

писанный и полностью отлаженный модуль с тем, чтобы он загружался

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

файл стандартных модулей можно с помощью утилиты TPUMOVER.EXE.

 

Кроме того, утилита TPUMOVER используется для удаления моду-

лей из библиотечного файла стандартных модулей Borland Pascal,

благодаря чему уменьшается его размер и количество памяти, необ-

ходимой для его загрузки.

 

Примечание: Более подробно об использовании утилиты

TPUMOVER см. в "Руководстве по инструментальным средствам и

утилитам".

 

Как вы вероятно поняли, писать собственные модули абсолютно

не сложно. Хорошо написанный, хорошо реализованный программный

модуль упрощает разработку программы; проблемы решаются только

один раз, а не повторно для каждой новой программы. Более того,

использование модулей обеспечивает простое средство для написания

больших программ.

 


 

B.Pascal 7 & Objects /UG - 176 -

 

────────────────────────────────────────────────────────────────────────────

Глава 8. Использование указателей

─────────────────────────────────────────────────────────────────

 

Указатель - это ссылка на данные или код вашей программы. Он

представляет адрес в памяти элемента, на который указывает. Ис-

пользование указателей позволяет писать большие и более гибкие

программы и особенно полезно, когда вы начинаете писать объект-

но-ориентированные программы.

 

Данная глава должна помочь вам лучше использовать указатели,

независимо от того, начинаете ли вы работать с Паскалем или уже

давно программируете на Паскале, но раньше не работали с указате-

лями. Она охватывает следующие темы:

 

* Зачем и когда используются указатели.

* Что такое указатель.

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

* Эффективная работа с указателями.

 

 

Для чего используются указатели?

─────────────────────────────────────────────────────────────────

 

Рано или поздно каждый программист, работающий на Паскале,

попадает в ситуацию, требующую использования указателей. Указате-

ли требуется применять в следующих случаях:

 

* Если ваша программа работает с большими объемами данных

(общий объем которых превышает 64К).

 

* Если ваша программа во время компиляция использует данные

неизвестного размера.

 

* Если программа использует временные буферы данных.

 

* Если ваша программа работает с несколькими типами данных.

 

* Если ваша программа использует связанные списки данных или

объектов.

 

Давайте подробнее рассмотрим каждую причину использования

указателей.

 

 

Работа с большими объемами данных

─────────────────────────────────────────────────────────────────

 

По мере того как программы становятся более сложными, и тре-

буются работа с большим количеством данных, область объемом в

64К, зарезервированная в Borland Pascal для данных, может ока-

заться недостаточной, чтобы содержать все необходимые программе

данные. Указатели позволяют вам обойти эту проблему.

 


 

B.Pascal 7 & Objects /UG - 177 -

 

Когда вы описываете в Borland Pascal глобальные переменные,

компилятор выделяет для них память в области, которая называется

сегментом данных. Сегмент данных имеет максимальный размер 64К.

Это означает, что общий объем всех ваших глобальных переменных не

может превышать 64К. Для многих программ этот предел значения не

имеет, но в некоторых случаях вам может потребоваться больший

объем.

 

Примечание: Локальные переменные не помещаются в сег-

мент данных и в пределе 64К не учитываются.

 

Предположим, например, что у вас есть программа, требующая

массива в 400 строк по 100 символов каждая. Для этого массива

требуется примерно 40К, что меньше максимума в 64К. Если осталь-

ные ваши переменные помещаются в оставшиеся 24К, массив такого

объема проблемы не представляет.

 

Но что если вам нужно два таких массива? Это потребовало бы

80К, и 64К сегмента данных не хватит. Чтобы работать с большими

объемами данных, вам нужно использовать динамически распределяе-

мую область памяти. Ваша программа может выделить в динамически

распределяемой области 80К, поддерживая указатель в виде ссылку

на адрес данных. Указатель занимает в сегменте данных только 4

килобайта.

 

Что такое динамически распределяемая область памяти?

 

Динамически распределяемая область памяти - это вся память,

которую ваша операционная система делает доступной для программы

и которая не используется ее кодом, сегментом данных и стеком.

Объемом распределяемой динамической памяти вы можете управлять с

помощью директивы компилятора $M.

 

Обычно в Borland Pascal вы можете зарезервировать память в

динамически распределяемой области, получить к ней доступ через

указатель, а затем снова освободить память. Подробности о распре-

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

найти ниже в разделе "Как использовать указатели?".

 

 

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

─────────────────────────────────────────────────────────────────

 

Некоторые элементы данных Borland Pascal (в частности, стро-

ки и массивы) требуют задания размеров во время компиляции, даже

если при выполнении программы вам не потребуется вся выделенная

память. Простым примером может быть программа, считывающая вводи-

мую пользователем строку, например, имя пользователь. Чтобы запи-

сать имя в обычной строковой переменной, вам потребовалось бы за-

резервировать достаточно памяти для максимальной возможной стро-

ки, даже если набранное имя содержит всего несколько букв. Если

вы распределяете переменные в динамически распределяемой области

памяти во время выполнения, то можете выделить точно столько


 

B.Pascal 7 & Objects /UG - 178 -

 

байт, сколько необходимо для фактической строки данных.

 

Это тривиальный пример, но в приложении, содержащем сотни и

тысячи таких элементов данных (таких как множественные окна или

считываемые из файлов списки) выделение точного объема пространс-

тва может вместо ситуации нехватки памяти привести к успешному

выполнению.

 

 

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

─────────────────────────────────────────────────────────────────

 

Указатели и динамически распределяемая область памяти осо-

бенно полезны в тех случаях, когда вам требуется временное выде-

ление памяти, и вы не хотите удерживать ее на все время выполне-

ния программы. Например, редактору файлов обычно требуется буфер

данных для каждого редактируемого файла. Вместо описания на этапе

компиляции, что вам необходимо определенное число буфером задан-

ного размера, которые всегда распределяются для файлов, вы можете

выделить их столько, сколько необходимо в каждый конкретный мо-

мент, что делает память доступной для других целей.

 

Другим общим примером использования временной памяти являет-

ся сортировка. Обычно когда вы сортируете большой объем данных,

то делаете копию массива, сортируете копию, а затем записываете

отсортированные данные обратно в исходный массив. Это сохраняет

целостность ваших данных, но требует также наличия во время сор-

тировки двух копий данных. Если вы хотите распределить сортируе-

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

тировать его и скопировать обратно в оригинал, а затем уничтожить

сортируемый массив, освободив память для других нужд.

 

 

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

─────────────────────────────────────────────────────────────────

 

Одной из общих причин использования указателей является

ссылка на переменные структуры данных, то есть записи или масси-

вы, которые не всегда имеют одну и ту же структуру. Например, вы

можете выделить блок памяти, зарезервированный для "протокола"

элементов строк различной длины, набранных в поле ввода данных.

Чтобы прочитать список протокола, подпрограмма должна просмотреть

блок и найти отдельные строки. Для указания начала блока вы може-

те использовать простой указатель. В этом случае указатель рабо-

тает аналогично передаче функции или процедуре нетипизированного

параметра var - вы просто хотите сообщить, где что-то находится,

без указания того, что это такое.

 

Примечание: О нетипизированных параметрах-переменных

рассказывается в Главе 9 ("Процедуры и функции") "Руководс-

тва по языку".

 

 


 

B.Pascal 7 & Objects /UG - 179 -

 

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

─────────────────────────────────────────────────────────────────

 

Одним из общих случаев использования указателей является со-

единение связанных списков записи. Во многих простых приложениях

типа баз данных вы можете размещать записи данных в массивах или

типизированных файлах, но иногда требуется что-то более гибкое

чем массив, который имеет фиксированный размер. Распределяя дина-

мические записи, так что каждое поле имеет запись, указывающую на

следующие записи, вы можете построить список, содержащий столько

элементов, сколько вам требуется.

 

 

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

─────────────────────────────────────────────────────────────────

 

Указатель - это какой-либо адрес в памяти вашего компьютера.

Это может быть адрес переменной, записи данных, либо процедуры

или функции. Обычно вам не важно, где расположен элемент в памя-

ти. Вы можете просто ссылаться на него по имени, и Borland Pascal

знает, где его нужно искать.

 

Именно это происходит, когда вы описываете переменную. Нап-

ример, если программа включает в себя следующий код, то вы указы-

ваете компилятору на необходимость зарезервировать область в па-

мяти, на которую будете ссылаться по имени SomeNumber.

 

var SomeNumber: Integer;

 

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

памяти. Именно для этого задается имя.

 

Адрес размещения SomeNumber в памяти можно найти с помощью

операции @. @SomeNumber - это адрес вашей целочисленной перемен-

ной. Вы можете присвоить этот адрес переменной-указателю, то есть

переменной, содержащей адрес данных или кода в памяти.

 

 

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

─────────────────────────────────────────────────────────────────

 

Чтобы хранить указатели, вам требуется переменная-указатель,

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

(или тип "указатель"). Простейшим ссылочным типом является стан-

дартный тип с именем Pointer. Переменная типа Pointer - это общий

(нетипизированный) указатель, то есть, просто адрес. Он не содер-

жит информации о том, на что он указывает.

 

Таким образом, чтобы использовать тот же пример SomeNumber,

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

 

var

SomeNumber: Integer;


 

B.Pascal 7 & Objects /UG - 180 -

 

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;

 

 

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

─────────────────────────────────────────────────────────────────

 

До сих пор мы видели, как можно присваивать указателям зна-

чения, но если вы не можете получить значения обратно, польза от

этого невелика. Разыменовав типизированный указатель, вы можете

интерпретировать так, как если бы это была переменная типа, на

которую он указывает. Чтобы разыменовать указатель, поместите

символ каре (^) после идентификатора указателя.

 

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

 


 

B.Pascal 7 & Objects /UG - 181 -

 

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.

 

Пример 8.1 Простые примеры разыменования указателей.

 

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

 

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

SomeNumber }

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

 

Если вы поймете разницу между этими двумя операторами, то

поймете основные моменты в использовании указателей. Первый опе-

ратор присваивает адрес переменной AnotherAddress; он сообщает

ей, куда нужно указывать. Второй оператор присваивает новое зна-

чение элементу, на который указывает AnotherAddress. На Рис. 8.1

графически показано, как изменяется переменная.

 

┌──────────┐┌───────────┐┌───────────┐┌───────────┐

SomeNumber │ 17 ││ 17 ││ 17 ││ 99 │

├──────────┤├───────────┤├───────────┤├───────────┤

│ не ││ ││ ││ │

SomeAddress │определено││@SomeNumber││@SomeNumber││@SomeNumber│

├──────────┤├───────────┤├───────────┤├───────────┤

│ не ││ не ││ ││ │

AnotherAddress│определено││определено ││@SomeNumber││@SomeNumber│

└──────────┘└───────────┘└───────────┘└───────────┘

^ ^ ^ ^

SomeNumber:= 17; │ │ │

SomeAddress:= │ │

@SomeNumber; │ │

AnotherAddress │

:= SomeAddress: │

AnotherAddress^

:= 99;

 

 


Дата добавления: 2015-09-30; просмотров: 21 | Нарушение авторских прав







mybiblioteka.su - 2015-2024 год. (0.069 сек.)







<== предыдущая лекция | следующая лекция ==>