В 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, используе- мую для преобразования строки с завершающим нулем в строку Паска- ля. Приведем краткое описание каждой функции: Функции модуля Strings ---------------T------------------------------------------------ ¦ Функция ¦ Описание ¦ +--------------+------------------------------------------------+ ¦ 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 ¦ Выделяет для строки память в динамически рас-¦ ¦ ¦ пределяемой области. ¦ +--------------+------------------------------------------------+ ¦ StrPas ¦ Преобразует строку с завершающим нулем в строку¦ ¦ ¦ Паскаля. ¦ +--------------+------------------------------------------------+ ¦ StrPCopy ¦ Копирует строку Паскаля в строку с завершающим¦ ¦ ¦ нулем и возвращает указатель на строку с завер-¦ ¦ ¦ шающим нулем. ¦ +--------------+------------------------------------------------+ ¦ StrPos ¦ Возвращает указатель на первое вхождение задан-¦ ¦ ¦ ной подстроки в строке, или nil, если подстрока¦ ¦ ¦ в строке не содержится. ¦ +--------------+------------------------------------------------+ ¦ StrRScan ¦ Возвращает указатель на последнее вхождение¦ ¦ ¦ указанного символа в строку, или nil, если сим-¦ ¦ ¦ вол в строке отсутствует. ¦ +--------------+------------------------------------------------+ ¦ StrScan ¦ Возвращает указатель на первое вхождение ука-¦ ¦ ¦ занного символа в строку, или nil, если символ¦ ¦ ¦ в строке отсутствует. ¦ +--------------+------------------------------------------------+ ¦ StrUpper ¦ Преобразует строку в верхний регистр и возвра-¦ ¦ ¦ щает указатель на нее. ¦ L--------------+-------------------------------------------------Использование строк с завершающим нулем
Строки с завершающим нулем хранятся в виде символьных масси- вов с нулевой базой (начинающихся с 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; Более всего строки Паскаля и строки с завершающим нулем от- личаются интенсивностью использования указателей. Borland Pascal выполняет операции с этими указателями, используя набор правил расширенного синтаксиса. Кроме того, в Borland Pascal имеется встроенный тип PChar, который представляет собой указатель на строку с завершающим нулем. В модуле System тип PChar определяет- ся следующим образом: type PChar = ^Char; Правилами расширенного синтаксиса управляет директива компи- лятора $X. В состоянии {$X+} (по умолчанию) расширенный синтаксис разрешен. Правила расширенного синтаксиса описываются в следующих разделах.Символьные указатели и строковые литералы
При разрешении расширенного синтаксиса строковый литерал совместим по присваиванию с типом 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. 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;Индексирование символьного указателя
Так как символьный массив с нулевой базой совместим с сим- вольным указателем, символьный указатель можно индексировать ана- логично символьному массиву с нулевой базой. 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); 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 указывают на один и тот же массив символов. Если эти два указателя указывают на разные символьные массивы, то ре- зультат непредсказуем. Стандартный синтаксис 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 ("Справочник по библиотеке") "Справочного руководства прог- раммиста".Пример использования функций с завершающим нулем
Приведем пример исходного кода, показывающий, как можно ис- пользовать некоторые функции обработки строк. Этот пример исполь- зован при разработке функции 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; 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;
Назад | Содержание | Вперед