Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Руководство по языку Паскаль 1.doc
Скачиваний:
12
Добавлен:
22.04.2019
Размер:
2.48 Mб
Скачать

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

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

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

торые называются строками, завершающимися нулем. Благодаря расши-

ренному синтаксису Borland Pascal и модулю Strings ваши программы

(как для DOS, так и для Windows) могут использовать строки с за-

вершающим нулем путем задания в операторе uses модуля Strings.

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

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

В Borland Pascal строки обычного типа (String) хранятся как

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

симальная длина строки в Паскале равна 255 символам. Таким обра-

зом, строка Паскаля занимает от 1 до 256 байт памяти.

Строки с завершающим нулем не содержат байта длины. Вместо

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

которыми следует символ NULL (#0). Никаких ограничений на длину

строк с завершающим нулем не накладывается, но 16-разрядная архи-

тектура DOS и Windows ограничивает их размер 65535 символами.

Функции модуля Strings

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

Borland Pascal не имеет встроенных подпрограмм, предназна-

ченных специально для работы со строками с завершающим нулем. Эти

функции вы можете найти в модуле Strings. Среди них вы найдете

функцию StrPCopy, которую можно использовать для копирования

строки Паскаля в строку с завершающим нулем, и StrPos, используе-

мую для преобразования строки с завершающим нулем в строку Паска-

ля. Приведем краткое описание каждой функции:

B.Pascal 7 & Objects/LR - 298 -

Функции модуля Strings

┌──────────────┬────────────────────────────────────────────────┐

│ Функция │ Описание │

├──────────────┼────────────────────────────────────────────────┤

│ StrCat │ Добавляет исходную строку к концу целевой стро-│

│ │ ки и возвращает указатель на целевую строку. │

├──────────────┼────────────────────────────────────────────────┤

│ StrComp │ Сравнивает две строки S1 и S2. Возвращает│

│ │ значение < 0, если S1 < S2, равное 0, если S1 =│

│ │ S2 и > 0, если S1 > S2. │

├──────────────┼────────────────────────────────────────────────┤

│ StrCopy │ Копирует исходную строку в целевую строку и│

│ │ возвращает указатель на целевую строку. │

├──────────────┼────────────────────────────────────────────────┤

│ StrECopy │ Копирует исходную строку в целевую строку и│

│ │ возвращает указатель на конец целевой строки. │

├──────────────┼────────────────────────────────────────────────┤

│ StrIComp │ Сравнивает две строки без различия регистра│

│ │ символов. │

├──────────────┼────────────────────────────────────────────────┤

│ StrLCat │ Присоединяет исходную строку к концу целевой│

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

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

│ │ симума. Возвращается указатель на строку-ре-│

│ │ зультат. │

├──────────────┼────────────────────────────────────────────────┤

│ StrLComp │ Сравнивает две строки с заданной максимальной│

│ │ длиной. │

├──────────────┼────────────────────────────────────────────────┤

│ StrLCopy │ Копирует заданное число символов из исходной│

│ │ строки в целевую строку и возвращает указатель│

│ │ на целевую строку. │

├──────────────┼────────────────────────────────────────────────┤

│ StrEnd │ Возвращает указатель на конец строки, то есть│

│ │ указатель на завершающий строку нулевой символ.│

├──────────────┼────────────────────────────────────────────────┤

│ StrDispose │ Уничтожает ранее выделенную строку. │

├──────────────┼────────────────────────────────────────────────┤

│ StrLen │ Возвращает длину строки. │

├──────────────┼────────────────────────────────────────────────┤

│ StrLIComp │ Сравнивает две строки с заданной максимальной│

│ │ длиной без различия регистра символов. │

├──────────────┼────────────────────────────────────────────────┤

│ StrLower │ Преобразует строку в нижний регистр и возвраща-│

│ │ ет указатель на нее. │

├──────────────┼────────────────────────────────────────────────┤

│ StrMove │ Перемещает блок символов из исходной строки в│

│ │ целевую строку и возвращает указатель на целе-│

│ │ вую строку. Два блока могут перекрываться. │

├──────────────┼────────────────────────────────────────────────┤

│ StrNew │ Выделяет для строки память в динамически рас-│

│ │ пределяемой области. │

├──────────────┼────────────────────────────────────────────────┤

B.Pascal 7 & Objects/LR - 299 -

│ StrPas │ Преобразует строку с завершающим нулем в строку│

│ │ Паскаля. │

├──────────────┼────────────────────────────────────────────────┤

│ StrPCopy │ Копирует строку Паскаля в строку с завершающим│

│ │ нулем и возвращает указатель на строку с завер-│

│ │ шающим нулем. │

├──────────────┼────────────────────────────────────────────────┤

│ StrPos │ Возвращает указатель на первое вхождение задан-│

│ │ ной подстроки в строке, или nil, если подстрока│

│ │ в строке не содержится. │

├──────────────┼────────────────────────────────────────────────┤

│ StrRScan │ Возвращает указатель на последнее вхождение│

│ │ указанного символа в строку, или nil, если сим-│

│ │ вол в строке отсутствует. │

├──────────────┼────────────────────────────────────────────────┤

│ StrScan │ Возвращает указатель на первое вхождение ука-│

│ │ занного символа в строку, или nil, если символ│

│ │ в строке отсутствует. │

├──────────────┼────────────────────────────────────────────────┤

│ StrUpper │ Преобразует строку в верхний регистр и возвра-│

│ │ щает указатель на нее. │

└──────────────┴────────────────────────────────────────────────┘

Использование строк с завершающим нулем

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

Строки с завершающим нулем хранятся в виде символьных масси-

вов с нулевой базой (начинающихся с 0) с индексом целого типа, то

есть в виде массива:

array[0..X] of Char;

где X - положительное ненулевое целое число. Такие массивы назы-

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

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

гут использоваться для хранения завершающихся нулем строк.

type

TIdentifier = array[0..15] of Char;

TFileName = array[0..79] of Char;

TMemoText = array[0..1023] of Char;

B.Pascal 7 & Objects/LR - 300 -

Более всего строки Паскаля и строки с завершающим нулем от-

личаются интенсивностью использования указателей. Borland Pascal

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

расширенного синтаксиса. Кроме того, в Borland Pascal имеется

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

строку с завершающим нулем. В модуле System тип PChar определяет-

ся следующим образом:

type PChar = ^Char;

Правилами расширенного синтаксиса управляет директива компи-

лятора $X. В состоянии {$X+} (по умолчанию) расширенный синтаксис

разрешен. Правила расширенного синтаксиса описываются в следующих

разделах.

B.Pascal 7 & Objects/LR - 301 -

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

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

При разрешении расширенного синтаксиса строковый литерал

совместим по присваиванию с типом PChar. Это означает, что пере-

менной типа PChar можно присвоить строковый литерал. Например:

var

P: PChar;

.

.

begin

P := 'Привет...';

end;

В результате такого присваивания указатель указывает на об-

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

копией строкового литерала. Компилятор записывает строковые лите-

ралы в сегмент данных, аналогично описанию "скрытых" типизирован-

ных констант:

const

TempString: array[0..14] of Char = 'Привет...'#0;

var

P: PChar;

.

.

begin

P := @TempString;

end;

Когда соответствующие формальные параметры имеют тип Char,

строковые литералы вы можете использовать как фактические пара-

метры при вызовах процедур и функций. Например, если имеется про-

цедура с описанием:

procedure PrintStr(Str: PChar);

то допустимы следующие вызовы процедуры:

procedure PrintStr('Строка для проверки');

PrintStr(#10#13);

Аналогично тому, как это происходит при присваивании, компи-

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

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

на эту область памяти в параметре Str процедуры PrintStr.

Наконец, типизированная константа типа PChar может инициали-

зироваться строковой константой. Это справедливо также для струк-

турных типов, таких как массивы PChar и записи, а также объекты

PChar.

B.Pascal 7 & Objects/LR - 302 -

const

Message: PChar = 'Program terminated';

Prompt: PChar = 'Enter values: ';

Digits; array [0..9] of PChar = {

'Zero', 'One', 'Two', 'Three', 'Four', 'Five',

'Six', 'Seven', Eight', 'Nine'};

Строковая выражение-константа всегда вычисляется как строка

Паскаля, даже если она инициализируется как типизированная конс-

танта типа PChar. Таким образом, строковое выражение-константа

всегда ограничено длиной в 255 символов.

Символьные указатели и символьные массивы

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

Если вы с помощью директивы $X разрешаете расширенный син-

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

PChar. Это означает, что там, где предполагается использование

типа PChar, может использоваться символьный массив с нулевой ба-

зой. Когда символьный массив используется вместо значения PChar,

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

значение которой соответствует адресу первого элемента массива.

Например:

var

A: array[0..63] of Char;

P: PChar;

.

.

.

begin

P := A;

PrintStr(A);

PrintStr(P);

end;

Благодаря оператору присваивания P теперь указывает на пер-

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

и тем же значением.

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

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

терала, имеющего меньшую длину, чем размер массива. Оставшиеся

символы устанавливаются в значение NULL (#0), и массив будет со-

держать строку с завершающим нулем.

type

TFileName = array[0..79] of Char;

const

FileNameBuf: TfileName = 'TEST.PAS';

FileNamePtr: PCahr = FileNameBuf;

B.Pascal 7 & Objects/LR - 303 -

Индексирование символьного указателя

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

Так как символьный массив с нулевой базой совместим с сим-

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

логично символьному массиву с нулевой базой.

var

A: array[0..63] of Char;

P: PChar;

Ch: Char;

.

.

.

begin

P := A;

Ch := A[5];

Ch := P[5];

end;

Оба последних присваивания присваивают Ch значение, содержа-

щееся в шестом символе-элементе A.

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

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

менованием. Таким образом, P[0] эквивалентно P^ и задает символ,

на который указывает P. P[1] задает символ справа от того, на ко-

торый указывает P, P[2] задает следующий символ и т.д. Для целей

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

описывался:

type

TCharArray = array[0..65535] of Char;

Pchar = ^TCharArray;

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

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

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

щим нулем, на которую указывает символьный указатель.

Показанная ниже функция StrUpper иллюстрирует использование

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

лем в верхний регистр.

function StrUpper(Srt: Pchar): Pchar;

var

I: Word;

begin

I := 0;

while Str[I] <> #0 do

begin

Str[I] := UpCase(Str[I]);

Inc(I);

B.Pascal 7 & Objects/LR - 304 -

end;

StrUpper := Str;

end;

Обратите внимание, что StrUppper - это функция, а не проце-

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

ей в качестве параметра. Так как расширенный синтаксис допускает

игнорирование результата функции, StrUpper может интерпретиро-

ваться, как процедура:

StrUpper(A);

PrintStr(A);

Однако, StrUpper всегда возвращает передаваемое ей значение,

приведенные выше операторы можно скомбинировать в один:

PrintStr(StrUpper(A));

Вложенные вызовы функций работы со строками с завершающим

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

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

строками.

Операции с символьными указателями

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

Расширенный синтаксис Borland Pascal позволяет использовать

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

личения или уменьшения смещения в значении указателя можно ис-

пользовать операции плюс (+) и минус (-). Операцию минус (-) мож-

но использовать для вычисления расстояния (разности смещений)

между двумя символьными указателями. Предположим, что P и Q

представляют собой значения тип PChar, а I - значение типа Word.

Тогда допустимы следующие конструкции:

P + I I прибавляется к смещению P

I + P I прибавляется к смещению P

P - I I вычитается из смещения P

P - Q Смещение Q вычитается из смещения P

В операциях P + I и I + P I прибавляется к адресу, задавае-

мому P. При этом получается указатель, который указывает на I

символов после P. В операции P - I I вычитается из адреса, зада-

ваемого P, и получается указатель, указывающий на I символов до

P.

Операция P - Q вычисляет расстояние между Q (младший адрес)

и P (старший адрес). При этом возвращается результат типа Word,

показывающий число символов между Q и P. Эта операция предполага-

ет, что P и Q указывают на один и тот же массив символов. Если

эти два указателя указывают на разные символьные массивы, то ре-

зультат непредсказуем.

B.Pascal 7 & Objects/LR - 305 -

Стандартный синтаксис Borland Pascal позволяет при сравнении

указателей определять только их равенство или неравенство. Расши-

ренный синтаксис (разрешенный по директиве компилятора {$X+})

позволяет применять операции <, >, <= и <= к значениям PChar. За-

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

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

лов. По этой причине сравниваются только смещения указателей. Ес-

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

результат не определен.

var

A, B: array[0..79] of Char;

P, Q: PChar;

begin

P := A; { P указывает на A[0] }

Q := A + 5; { Q указывает на A[5] }

if P < Q then ...; { допустимая проверка,

результат - True }

Q := B; { Q указывает на B[0] }

if P < Q then ...; { результат не определен }

end;

Подробнее об операциях с PChar рассказывается в Главе 6.

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

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

Расширенный синтаксис Borland Pascal позволяет применять к

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

ReadLn и Val, а к символьным массива с нулевой базой и символьным

указателям - стандартные процедуры Write, WriteLn, Val, Assign и

Rename. Более подробные описания этих процедур можно найти в Гла-

ве 1 ("Справочник по библиотеке") "Справочного руководства прог-

раммиста".

B.Pascal 7 & Objects/LR - 306 -

Пример использования функций с завершающим нулем

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

Приведем пример исходного кода, показывающий, как можно ис-

пользовать некоторые функции обработки строк. Этот пример исполь-

зован при разработке функции FileSplit в модуле WinDos.

{ максимальные размеры компонентов имени файла }

const

fsPathName = 79; { имя маршрута }

fsDirectory = 67; { имя каталога }

fsFileName = 8; { имя файла }

fsExtension = 4; { расширение имени файла }

{ флаги, возвращаемые FileSplit }

const

fcWildcards = $0008 { трафаретные символы }

fcDirectory = $0004 { имя каталога }

fcFileName = $0002 { имя файла }

fcExtension = $0001 { расширение имени файла }

{ FileSplit разбивает имя файла, заданное маршрутом, на три }

{ компонента. Dir принимает значение диска и каталога с }

{ предшествующей и завершающей обратной косой чертой, Name }

{ принимает значение имени файла, а Ext - расширения с }

{ предшествующей точкой. Если компонент строки-параметра }

{ равен NIL, то соответствующая часть маршрута не }

{ записывается. Если маршрут не содержит данного компонента, }

{ то возвращаемая строка компонента будет пустой. }

{ Максимальные длины строк, возвращаемых в Dir, Name и Ext, }

{ определяются битовыми масками fsDirectory, fsFileName, }

{ fsExtension. Возвращаемое значение представляет собой }

{ комбинацию битовых масок fсDirectory, fсFileName и }

{ fсExtension, показывающую, какие компоненты присутствуют в }

{ маршруте. Если имя и расширение содержат трафаретные }

{ символы (* и ?), то в возвращаемом значении устанавливается }

{ флаг fcWildcards. }

function FileSplit(Path, Dir, Name, Ext: PChar): Word;

var

DirLen, NameLEn, Flags: Word;

NamePtr, ExtPtr: PChar;

begin

NamePtr := StrRScan(Path, '/');

if NamePtr = nil then NamePtr := StrRScan(Path, ':');

if NamePtr = nil then NamePtr := Path else Inc(NamePtr);

ExtPtr := StrScan(NamePtr, '.');

if ExtPtr = nil then ExtPtr := StrEnd(NamePtr);

DirLen := NamePtr - Path;

if DirLen > fsDirectory then DirLen := fsDirectory;

NameLen := ExtPtr - NamePtr;

B.Pascal 7 & Objects/LR - 307 -

if NameLen > fsFilename then NameLen := fsFileName;

Flags := 0;

if (StrScan(NamePtr, '?') <> nil) or

(StrScan(NamePtr, '*') <> nil) then

Falgs := fcWildcards;

if DirLen <> 0 then Flags := Flags or fcDirectory;

if NameLen <> 0 then Flags := Flags or fcFilename;

if ExtPtr[0] <> #0 then Flags := Flags or fcExtension;

if Dir <> nil then StrLCopy(Dir, Path, DirLen);

if Name <> nil then StrLCopy(Name, NamePtr, NameLen);

if Ext <> nil then StrLCopy(Ext, ExtPtr, fsExtension);

FileSplit := Flags:

end;

B.Pascal 7 & Objects/LR - 308 -

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

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]