Главная » Delphi » Типы данных Object Pascal

0

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

Сравнение типов данных

Основные типы  данных  Object Pascal  схожи  с типами данных  языков Java,  C и Visual Basic. В табл. 2.5 приведено сравнение типов  данных  этих  языков. Настоятель но рекомендуем пометить настоящую  страницу закладкой —  она  содержит отличный справочный материал, который будет полезен при  вызове функций из динамически компонуемых библиотек, созданных другими компиляторами.

Таблица 2.5. Сравнение типов данных разных языков программирования

Тип переменной

Pascal

Java

C/C++

Visual Basic

8 битовое целое  со

ShortInt

byte

char

Нет

знаком

8 битовое целое  без

Byte

Нет

BYTE,

Byte

знака

unsigned short

16 битовое целое  со

SmallInt

short

short

Short

знаком

16 битовое целое  без знака

Word

Нет

unsigned short

Нет

32 битовое целое  со

Integer,

int

int, long

Integer, Long

знаком

Longint

32 битовое целое  без знака

Cardinal,

LongWord

Нет

unsigned long

Нет

64 битовое целое  со

Int64

long

  int64

Нет

знаком

4 байтовое

Single

float

float

Single

вещественное

6 байтовое

Real48

Нет

Нет

Нет

вещественное

8 байтовое

Double

double

double

Double

вещественное

110 байтовое вещественное

Extended

Нет

long. dou- ble

Нет

64 битовое денежное

currency

Нет

Нет

Currency

8 битовое дата/время

TDateTime

Нет

Нет

Date

16 байтовый вариант

Variant,

Нет

VARIANT**,

Variant

OleVariant,

Variant***,

(По

TVarData

OleVari-

умолчанию)

ant***

1 байтовый символ

Char

Нет

char

Нет

Окончание табл. 2.5.

Тип переменной

Pascal

Java

C/C++

Visual Basic

2 байтовый символ

WideChar

char

WCHAR

Нет

Строка

ShortString

Нет

Нет

Нет

фиксированной длины

Динамическая строка

AnsiString

Нет

Ansi- String***

String

Строка с

PChar

Нет

char*

Нет

завершающим

нулевым символом

Строка 2 байтовых

PWideChar

Нет

LPCWSTR

Нет

символов

с завершающим

нулевым символом

Динамическая 2

байтовая строка

WideString

String**

Wide- String***

Нет

1 байтовое булево

Boolean,

ByteBool

boolean

(Любое

1 байтовое)

Нет

2 байтовое булево

WordBool

Нет

(Любое

Boolean

2 байтовое)

4 байтовое булево

BOOL,

LongBool

Нет

BOOL

Нет

** Не соответствующий элемент языка, а обычно используемая структура или класс

*** Классы Borland C++ Builder  для эмуляции соответствующих типов Object Pascal

НА ЗАМЕТКУ

При переносе 16-битового кода из Delphi 1.0 помните, что размер типов Integer и Cardinal вырос с 16 до 32 бит. Впрочем, это утверждение не совсем точно: в Delphi 2 и 3 тип Cardinal трактовался как 31-битовое целое без знака — в соответствии с те- ми результатами, которые могли быть получены при выполнении целочисленных опе- раций. Но уже в Delphi 4 тип Cardinal представлял собой истинное 32-битовое целое без знака.CОВЕТ

В Delphi 1, 2 и 3 тип Real определял 6-байтовое вещественное число. Такой тип присущ только языку Pascal и не совместим с другими языками программирования. В Delphi 4 этот тип стал синонимом типа Double. Старый 6-байтовый тип остался в языке под име- нем Real48, но с помощью директивы {$REALCOMPATIBILITY ON} можно заставить компилятор трактовать тип Real как 6-байтовый.

Символьные типы

Delphi  поддерживает три символьных типа данных.

•  AnsiChar — хорошо всем известный стандартный 1 байтовый символ ANSI.

•  WideChar — 2 байтовый символ Unicode.

•  Char —  сейчас  это  тип,  эквивалентный AnsiChar, но  Borland предупреждает, что  в последующих версиях он  может  измениться и стать  эквивалентным WideChar.

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

НА ЗАМЕТКУ

Стандартная функция SizeOf() возвращает размер в байтах переменной любого ти-

па или экземпляра любого класса.

Многообразие строк

Строки представляют собой  типы  данных, используемые для представления групп символов. Каждый  язык  по своему  решает проблему  размещения в памяти и исполь зования строк.  Object  Pascal поддерживает несколько различных типов  строк, и, ис ходя из конкретной ситуации, можно выбирать тот или иной  строковый тип.

•  AnsiString — строковый тип Object  Pascal по умолчанию. Состоит из символов AnsiChar, длина  практически неограничена. Совместим также  со строками с завершающим нулевым символом.

•  ShortString —  остался в языке  для совместимости с Delphi 1. Максимальная длина составляет 255 символов.

•    WideString — по сути сходен с AnsiString. Единственное отличие  заключа

ется в том, что эта строка состоит из символов типа WideChar.

•  PChar — представляет собой  указатель  на строку  с завершающим нулевым  сим волом,  состоящую  из  символов типа  Char. Аналог  типов  char* или  lpstr в языке  C.

•  PAnsiChar — указатель на строку AnsiChar с завершающим нулевым символом.

•  PWideChar — указатель на строку WideChar с завершающим нулевым символом.

По умолчанию при объявлении в коде строковой переменной (тип string) ком

пилятор полагает, что создается строка типа AnsiString:

var

S: string;        // Переменная S имеет тип AnsiString

Для  изменения принимаемого по умолчанию типа  строки используется директива компилятора $H. Ее положительное (по умолчанию) значение определяет использова ние  в качестве стандартного строкового типа  AnsiString, отрицательное —  Short- String. Вот пример использования директивы $H для изменения строкового типа,  вы бираемого по умолчанию:

var

{$H-}

S1: string;       // Переменная S1 имеет тип ShortString

{$H+}

S2: string;       // Переменная S2 имеет тип AnsiString

Исключением из этого  правила являются строки, объявленные с заранее установ ленным фиксированным размером. Если заданная длина не превышает 255 символов, такие строки всегда имеют тип ShortString:

var

S: string[63];         // Это строка типа ShortString

// размером 63 символа

Тип AnsiString

Тип   AnsiString,  известный  как  “длинная  строка”  (long   string),  был  введен   в Delphi  2.0 в ответ  на требования пользователей отменить 255 символьное ограниче ние на длину строки.

Хотя  в применении тип  AnsiString практически ничем  не отличается от  своего предшественника, память  для него выделяется динамически, а для ее освобождения применяется технология автоматической “уборки  мусора”  (garbage collect). Благодаря этому  AnsiString является типом   с  управляемым  временем жизни  (lifetime managed). Object  Pascal сам автоматически выделяет память  для временных строк, так что об этом не придется беспокоиться (как и у языка C), а также единолично заботится о том, чтобы строка всегда  была  с завершающим нулевым  символом (обеспечивая тем самым  ее со вместимость с интерфейсом API Win32). На самом деле тип AnsiString реализован как указатель  на структуру,  размещенную в распределяемой памяти (heap), и схематически показан на рис. 2.1.

Рис. 2.1. Размещение AnsiString в памяти

CОВЕТ

Полный внутренний формат длинной строки компанией Borland не документирован, а следовательно, она оставляет за собой право изменять его в дальнейших версиях языка. Поэтому приведенная здесь информация о структуре AnsiString служит толь- ко для того, чтобы облегчить понимание ее функционирования, однако использовать эти сведения для создания реальных программ не стоит.

Разработчики программ, которые избегали использования внутренней структуры строк, при переходе от Delphi 1 к Delphi 2 смогли перекомпилировать свои программы без проблем. Те же, кто опирались на внутренний формат строки (например на то, что ну- левой символ строки содержит ее длину), должны были соответствующим образом изменить свой код.Как показано на рис. 2.1, размещенная в памяти строка типа AnsiString обладает счетчиком ссылок (reference  counted),  содержащим количество строковых перемен ных, ссылающихся на одно и то же место в физической памяти. Таким  образом копи рование строки выполняется очень  быстро, поскольку  копируется не сама строка, а лишь указатель  на нее (значение счетчика при  этом  увеличивается). Если две или бо лее переменных типа AnsiString, обладающих ссылкой на одну и ту же запись  в фи зической памяти, пытаются модифицировать ее,  то  диспетчер  памяти  Delphi (Delphi memory manager) использует методику  копирования для записи (copy on write),  которая позволяет второму  процессу  не ждать,  пока  модификация строки будет завершена, а перенести ссылку на вновь  созданную  в памяти физическую строку.  Следующий  при мер иллюстрирует эту концепцию:

var

S1, S2: string;

begin

// поместить строку в S1, счетчик ссылок S1 равен 1

S1 := ‘And now for something… ‘;

S2 := S1;        // Теперь S2 ссылается на S1.

// Счетчик ссылок S1 равен 2.

// Строка S2 изменяется, поэтому ее содержимое копируется в

// новую область памяти, а значение счетчика ссылок S1

// уменьшается на единицу

S2 := S2 + ‘completely different!';

Типы с управляемым временем жизни

Помимо AnsiString, в Delphi существует несколько других типов данных с управляе- мым временем жизни. Это динамические массивы WideString, Variant, OleVari- ant, interface и dispinterface. Далее в этой главе они будут описаны подробнее, а сейчас нас интересует только один вопрос: что такое управляемое время жизни и как это работает?

Подобные типы иногда называют типами “с уборкой мусора” (garbage-collected types).

Они используют некоторые ресурсы компьютера и автоматически освобождают их при выходе из области видимости. Естественно, то, какие именно ресурсы требуются тому или иному типу, зависит исключительно от него. Так, тип AnsiString использует па- мять компьютера для хранения своих данных, и при выходе из области видимости эта память должна быть освобождена.

Для глобальных переменных решение данной проблемы достаточно тривиально — соот- ветствующий код освобождения ресурсов помещается в завершающий код приложения. Поскольку при начальной инициализации происходит инициализация глобальных пере- менных нулевыми значениями, т.е. фактически значениями “не используется”, завер- шающий код может принимать решение о необходимости освобождения тех или иных ресурсов по состоянию глобальной переменной и выполнять “уборку мусора” только там, где это необходимо.

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

“уборки мусора” в часть finally блока. (Более подробная информация об обработкеисключений приведена в настоящей главе далее.) Чтобы лучше представить себе эти процессы, рассмотрим простейший пример:

procedure Foo;

var

S: string;

begin

// Тело процедуры. Переменная

// S используется здесь

end;

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

ден будет создать следующий код:

procedure Foo;

var

S: string;

begin

S := ”;

try

// Тело процедуры. Переменная

// S используется здесь

finally

// освобождение S происходит здесь

end;

end;

Строковые операции

Сложить две строки можно  либо  с помощью оператора +, либо  с помощью функ ции  Concat(). Предпочтительнее использовать оператор +, так  как функция  Con- cat() сохранена в основном из соображений совместимости с прежними версиями. Вот примеры использования оператора + и функции Concat():

{ Применение оператора + }

var

S, S2: string

begin

S := ‘Cookie ‘;

S2 := ‘Monster';

S := S + S2;        { Cookie Monster }

end.

{ Применение функции Concat() }

var

S, S2: string;

begin

S := ‘Cookie ‘;

S2 := ‘Monster';

S := Concat(S, S2); { Cookie Monster }

end.

НА ЗАМЕТКУ

При работе со строками в Object Pascal не забывайте, что использовать необходимо

одинарные кавычки (‘Это строка’).CОВЕТ

Функция Concat() — это одна из многих “волшебных палочек компилятора”, подобных функциям ReadLn() и WriteLn(), которые в Object Pascal не имеют определения. Такие функции и процедуры специально предназначены для того, чтобы принимать неопреде- ленное количество параметров или необязательные параметры. Поэтому эти функции не могут быть определены в терминах языка Object Pascal, а компилятор вынужден сделать исключение для каждой из них и создать код специального обращения к одной из “волшебных палочек” — вспомогательной функции (helper function), которые определены в модуле System. Вспомогательные функции реализованы на языке ассемблер специально для того, чтобы обойти правила языка Pascal.

Кроме функций поддержки работы со строками, Delphi обладает некоторыми другими функциями модуля SysUtils, предназначенными для упрощения работы со строками. О них можно узнать в разделе “String-handling routines (Pascal-style)” справочной сис- темы Delphi.

Длина строк и размещение в памяти

Вначале, при  объявлении, строка AnsiString не имеет  длины,  а значит, память для ее содержимого не выделяется. Чтобы выделить строке память, необходимо либо присвоить ей некоторое строковое значение (например литерал), либо использовать процедуру  SetLength(), как показано ниже.

var

S: string;             // Вначале строка не имеет длины

begin

S := ‘Doh!';           // Выделяется память, необходимая для

// размещения строки

{ или }

S := OtherString       // Увеличить счетчик ссылок другой строки

// (Предполагается, что строка OtherString уже имеет значение)

{ или }

SetLength(S, 4);       // Выделяется достаточно памяти, по крайней

// мере для размещения 4 символов

end;

Строку типа AnsiString можно  рассматривать как массив символов, но будьте ос торожны —  индекс  элемента массива  не  может  превышать длину  строки. Так,  пока занный ниже код приведет к ошибке.

var

S: string;

begin

S[1] := ‘a';       // Ошибка! Память для S не выделена!

end;

А этот код будет работать правильно:

var

S: string;

begin

SetLength(S, 1);

S[1] := ‘a';           // Теперь у S достаточно места, чтобы

// содержать один символ

end;

Совместимость с Win32

Как уже говорилось, строка типа  AnsiString всегда завершается нулевым  симво лом (null).  Поэтому  такая  строка вполне совместима с функциями  интерфейса  API Win32 или любыми  другими,  использующими параметры типа  PChar. Все, что  в дан ном случае необходимо, — это преобразование типа  string в тип PChar (о преобра зовании типов  в Object  Pascal можно  узнать  далее  в этой  главе).  Приведенный ниже пример демонстрирует вызов  функции  Win32  GetWindowsDirectory(), которой в качестве параметров передается указатель на буфер PChar и его размер.

var

S: string;

begin

SetLength(S, 256); // Важно! Сначала выделяем память для строки

// Теперь, после вызова функции, S будет содержать имя каталога

GetWindowsDirectory(PChar(S), 256);

end;

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

procedure RealizeLength(var S: string);

begin

SetLength(S, StrLen(PChar(S)));

end;

Вызов  процедуры RealizeLength() завершает преобразование строки AnsiS- tring в строку PChar:

var

S: string;

begin

SetLength(S, 256); // Важно! Сначала выделяем память для строки

// Теперь, после вызова функции, S будет содержать имя каталога

GetWindowsDirectory(PChar(S), 256);

RealizeLength(S);      // установить длину S по символу null

end;

CОВЕТ

Проявляйте определенную осторожность при приведении типов string к типу PChar. Поскольку string — это тип с управляемым временем жизни, следует обратить вни- мание на область видимости соответствующих переменных. Так, если сделать при- своение типа P := PChar(Str), а область видимости P больше, чем Str, результат может оказаться плачевным.

Вопросы переносимости

При  переносе на новую  32 битовую  платформу  старых  16 битовых приложений, созданных с помощью Delphi  1.0 и использующих тип AnsiString, необходимо пом нить следующее.•  Там,  где  применялся тип  PString (указатель на  ShortString),  следует  ис пользовать тип  String. Помните, что  AnsiString представляет собой  указа тель на строку.

•   Больше нельзя использовать нулевой  элемент строки (как массива)  для возвра щения  ее длины. Теперь для этого необходимо прибегать к функции Length(), а для определения или установки нового значения длины  строки — к процедуре SetLength().

•  Для  приведения типов   строк   между  String и  PChar больше   не  требуются функции  StrPas() и StrPCopy(). Как  уже было  сказано, можно  выполнять прямое преобразование типа  AnsiString в PChar. При  копировании содер жимого    PChar в   AnsiString можно   использовать  обычное  присвоение: StringVar := PCharVar;.

CОВЕТ

Не забывайте, что для установки длины строк типа AnsiString должна использовать- ся процедура SetLength(). Прежняя практика прямого обращения к нулевому эле- менту коротких строк здесь не применима. Это замечание следует помнить при пере- носе 16-разрядных приложений Delphi 1.0 в 32-разрядную среду.

Тип ShortString

Ветераны Delphi помнят, что  ShortString —  это  тип  String в Delphi  1.0, он же тип с байтом длины строки (length byte strings), он же тип  строки Pascal (Pascal  string). Еще раз напомним, что директива компилятора $H позволяет выбрать, какой  именно тип будет подразумеваться под именем  String — AnsiString или ShortString.

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

255 байт,  а вся строка в памяти не может  занимать более  256 байт  (255 байт  строки и один байт длины). Как и в случае с типом  AnsiString, при работе со строками Short- String не нужно заботиться о выделении памяти для временных строк  или ее освобож дении — всю эту работу компилятор берет на себя (в отличие от языка C).

На рис. 2.2 показано размещение строки ShortString в памяти. Компилятор можно  заставить встраивать в исполняемый файл  специальный код, ко торый осуществляет перехват и обработку ошибок выхода индекса за допустимые пределы в процессе выполнения программы. Для этого  необходимо установить флажок Range Checking (Проверка диапазона) во вкладке Compiler диалогового окна Project Options.

CОВЕТ

Несмотря на то, что включение в программу механизма проверки диапазона (range- checking) помогает избежать ошибок при работе со строками, в целом это немного снижает производительность приложения. Поэтому проверку диапазона используют обычно во время разработки и отладки приложения, а при компиляции окончательной версии его отключают.

В отличие от строк  типа AnsiString, строки ShortString не совместимы со стро ками в формате с завершающим нулевым символом. Чтобы использовать их в функциях интерфейса API Win32, необходима определенная предварительная обработка. Для это го можно  воспользоваться функцией ShortStringAsPChar(), которая входит  в состав уже упомянутого модуля STRUTILS.PAS. Текст такой функции приведен ниже.

function ShortStringAsPChar(var S: ShortString): PChar;

{ Функция добавляет к исходной строке завершающий нулевой символ, чтобы

она могла быть передана тем функциям, которые ожидают строку типа PChar.

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

begin

if Length(S) = High(S) then Dec(S[0]);

{ Усечение строки S, если она слишком длинная }

S[Ord(Length(S)) + 1] := #0;

{ Добавление нулевого символа в конец строки }

Result := @S[1];

{ Возвращает строку типа Pchar }

end;

CОВЕТ

Функции и процедуры интерфейса API Win32 работают только со строками с завер- шающим нулем. Не пытайтесь передать им строки типа ShortString непосредствен- но — программа просто не будет компилироваться. Можно существенно облегчить се- бе жизнь, если при работе с функциями интерфейса API использовать только длинные строки типа AnsiString.

Тип WideString

Это тип строк  с управляемым временем жизни, подобный типу AnsiString. Данные обоих  типов  располагаются в динамической памяти, обладают автоматической “уборкой мусора” и даже по назначению схожи. Но между типами WideString и AnsiString суще ствует три таких важных отличия:

•   Строка WideString состоит из символов WideChar, что делает ее совместимой со строками Unicode.

•   Строки WideString используют память, выделенную с помощью функции ин терфейса API SysAllocStrLen(), что  делает  их  совместимыми со  строками OLE BSTR.

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

Компилятор способен автоматически конвертировать строки типов  WideString

и AnsiString при присвоении, что и показано в следующем примере:

var

W: WideString;

S: string;

begin

W := ‘Margaritaville';

S := W;       // Преобразование WideString в AnsiString

S := ‘Come Monday';

W := S;       // Преобразование AnsiString в WideString

end;Для обеспечения работы со строками этого  типа  Object Pascal перегружает функ ции Concat(), Copy(), Insert(), Length(), Pos() и SetLength(), а также  опера торы  +, = и <> для работы с WideString. Таким  образом, следующий  код синтаксиче ски безупречен:

var

W1, W2: WideString;

P: Integer;

begin

W1 := ‘Enfield';

W2 := ‘field';

if W1 <> W2 then P := Pos(W1, W2);

end;

Как и в случае строк  типа AnsiString или ShortString, для ссылок на отдельные символы строки WideString можно использовать квадратные скобки:

var

W: WideString;

C: WideChar;

begin

W := ‘Ebony and Ivory living in perfect harmony';

C := W[Length(W)];      // C содержит последний символ строки W

end;

Строки с завершающим нулевым символом

Ранее  уже говорилось, что в Delphi  существует три  различных типа  строк  с завер шающим нулевым символом: PChar, PAnsiChar и PWideChar. Как и следует из их на званий, это  строки с завершающим нулем,  соответствующие трем  основным типам строк  Delphi. Впоследствии в настоящей главе под типом  PChar будем подразумевать именно  эти   типы   строк.   В  основном  тип   PChar обеспечивает  совместимость  с Delphi 1.0 и работу  с интерфейсом API Win32,  широко использующим строки с завер шающим  нулевым  символом. Тип  PChar определяется как указатель  на  строку  с за вершающим нулевым  символом. (Более подробная информация об указателях приве дена в этой  главе далее.)  В отличие от строк  AnsiString и WideString, память  для строк  типа  PChar автоматически не выделяется (и не освобождается). Это означает, что для тех строк, на которые указывают  данные указатели, память  потребуется выде лять  вручную —  с помощью одной  из существующих  в Object  Pascal функций выделе ния памяти. Теоретически длина строки PChar может  достигать 4 Гбайт.  Ее размеще ние в памяти показано на рис. 2.3.

Рис. 2.3. Размещение строки типа PChar в памятиCОВЕТ

Поскольку в большинстве случаев вместо типа PChar можно использовать тип AnsiS- tring, рекомендуется применять его везде, где это возможно. При этом удается из- бежать множества неприятностей, связанных с выделением и освобождением памяти, поскольку при работе с AnsiString компилятор берет заботу об этом на себя.

Как  уже отмечалось, переменные типа  PChar требуют  непосредственного выделе ния  и освобождения буферов, содержащих соответствующие строки. Обычно выделе ние памяти осуществляется с помощью функции StrAlloc(), однако  для создания бу феров PChar можно  применять и другие  из  них,  такие, например, как  AllocMem(), GetMem(), StrNew() или даже функции API VirtualAlloc(). Каждой  функции соот ветствует функция освобождения памяти (табл. 2.6).

Таблица 2.6. Функции выделения и освобождения памяти

Функция выделения памяти                                  Функция освобождения памяти

AllocMem()                     FreeMem() GlobalAlloc() GlobalFree() GetMem()   FreeMem() New()                          Dispose() StrAlloc()    StrDispose() StrNew()                               StrDispose() VirtualAlloc()   VirtualFree()

Вот пример выделения памяти при работе с данными типа PChar и String:

var

P1, P2: PChar;

S1, S2: string;

begin

P1 := StrAlloc(64 * SizeOf(Char));

// P1 указывает на участок памяти для размещения 63 символов

StrPCopy(P1, ‘Delphi 6 ‘);      // Копирует

S1 := ‘Developer”s Guide'; // Помещает

набор символов в P1

текст в строку S1

P2 := StrNew(PChar(S1));        // P1

указывает на копию S1

StrCat(P1, P2);                 // Объединяет

P1 и P2

S2 := P1;                       // Теперь S2 содержит строку

// ‘Delphi 6 Developer’s Guide’

StrDispose(P1);                 // Освобождает буферы P1 и P2

StrDispose(P2);

end.

Обратите особое внимание на то,  что  при  выделении памяти для P1 использова лась функция SizeOf(Char). Вполне  вероятно, что в будущих версиях Delphi размер символа  может  измениться с одного  до двух байт,  а такой  способ  выделения памяти для строки будет корректно работать при любых изменениях в размере символа.Для  объединения двух строк   использовалась  функция StrCat() —   при  работе  с PChar нельзя применять оператор +, как это делается в случае со строками типа AnsiS- tring или ShortString.

Функция  StrNew() использовалась для выделения памяти строки P2 и одновре менного копирования в нее строки S1. Но  не следует забывать, что  память  при  этом выделяется в количестве, необходимом для хранения лишь  строки конкретного раз мера.  Попытка записи в такой  буфер  более  длинной строки приведет к ошибке  памя ти. Следующий пример иллюстрирует подобную ситуацию.

var

P1, P2: Pchar;

begin

P1 := StrNew(‘Hello ‘);

P2 := StrNew(‘World’);

// Выделена память только для P1 и P2

StrCat(P1, P2);              // ОСТОРОЖНО, запись за пределы

// выделенной памяти!

.

.

.

end;

CОВЕТ

Как и в случае с другими типами строк, для работы с типом PChar Object Pascal предостав- ляет различные функции и процедуры. Подробные сведения о них можно найти в разделе “String-handling routines (null-terminated)” справочной системы Delphi.

Источник: Тейксейра, Стив, Пачеко, Ксавье.   Borland Delphi 6. Руководство разработчика. : Пер.  с англ. — М. : Издательский дом “Вильямс”, 2002. —  1120 с. : ил. — Парал. тит. англ.

По теме:

  • Комментарии