«Любой дурак может написать программу, которую поймет компилятор. Хорошие программисты пишут программы, которые смогут понять другие программисты»
7. Поддержка строк с завершающим нулем
Эти строки (null-terminated strings) используются многими языками, в том числе и средой Windows. Строка с завершающим нулем представляет собой массив символов, индекс первого элемента которого – нулевой. Первый встречающийся в массиве символ с кодом 0 является признаком конца строки. В Object Pascal можно использовать строки с завершающим нулем, для чего имеются языковые средства, а также подпрограммы в модуле SysUtils.
Например, следующие объявления могут быть использованы для обработки таких строк:
type
TIdentifier = array[0..15] of Char;
TFileName = array[0..259] of Char;
TMemoText = array[0..1023] of WideChar;
Таким статически размещенным массивам (с нулевым первым индексом) можно присваивать строковые константы. Динамические массивы для этой цели использовать нельзя.
Использование указателей, массивов и строковых констант.
Для обработки строк с завершающим нулем можно использовать указатели типа PChar. Строковые константы совместимы по присваиванию с типами PChar and PWideChar types, которые представляют собой указатели на массивы Char and WideChar values. Например:
var P: PChar;
…
P := 'Hello world!';
Такой фрагмент эквивалентен следующей конструкции:
const TempString: array[0..12] of Char = 'Hello world!'#0;
var P: PChar;
…
P := @TempString;
Строковые константы можно также передавать любой подпрограмме, формальные параметры которой являются параметрами значениями или параметрами const типов PChar или PWideChar, например, StrUpper('Hello world!'). Как и в случае присваивания, компилятор генерирует строковую константу и передает ее адрес подпрограмме. Также строковые константы типа PChar или PWideChar можно создавать и таким способом:
const
Message: PChar = 'Program terminated';
Digits: array[0..9] of PChar = ('Zero', 'One', 'Two', 'Three', 'Four',
'Five', 'Six', 'Seven', 'Eight', 'Nine');
Символьные массивы с нулевым первым индексом совместимы с типами PChar и PWideChar. Когда такой массив используется вместо указателя, компилятор преобразует его в константный указатель, значение которого совпадает с адресом первого элемента массива. Например:
var
MyArray: array[0..32] of Char;
MyPointer: PChar;
begin
MyArray := 'Hello';
MyPointer := MyArray;
SomeProcedure(MyArray);
SomeProcedure(MyPointer);
end;
В этом фрагменте процедура SomeProcedure вызывается дважды с одним и тем же значением.
Указатель на строку можно индексировать, начиная с нуля, как массив. Индекс указывает смещение относительно начала строки и прибавляется к значению указателя для получения адреса символа перед разыменованием указателя. Для переменных типа PWideChar индекс автоматически умножается на 2. Значение P[-1] указывает на символ, предшествующий первому, и компилятор не контролирует эту ситуацию. Функция StrUpper иллюстрирует использование указателей:
Function StrUpper(Dest, Source: PChar; MaxLen: Integer): PChar;
var
i: Integer;
Begin
i := 0;
while (i < MaxLen) and (Source[i] <> #0) do
begin
Dest[i] := UpCase(Source[i]); Inc(i);
end;
Dest[i] := #0;
Result := Dest;
End;
Смешивание строк AnsiString и строк с завершающим нулем PChar.
Можно смешивать длинные строки AnsiString и строки с завершающим нулем PChar в выражениях и в операторах присваивания. Также можно передавать строки PChar подпрограммам с параметрами AnsiStrings. Можно также выполнять приведение типа (typecast). При этом применяются следующие правила:
• если S имеет тип AnsiString, PChar(S) возвращает указатель на первый символ строки. Например, если Str1 and Str2 являются строками AnsiString, можно вызвать функцию MessageBox Win32 API таким образом:
MessageBox(0, PChar(Str1), PChar(Str2), MB_OK);
• можно также использовать выражение Pointer(S) для приведения длинной строки к нетипизированному указателю. Если при этом строка является пустой, выражение будет равно nil.
• при приведении типа переменной AnsiString к указателю, значение последнего остается корректным до тех пор, пока переменной не будет присвоено новое значение или пока переменная будет находиться в области видимости
• когда выражение типа AnsiString приводится к типу указатель, указатель должен обычно считаться доступным только по чтению. Этот указатель можно использовать для модификации строки с осторожностью при выполнении всех следующих условий:
а) выражение является переменной;
б) строка не является пустой
в) строка является единственной, т.е. число ссылок на нее равно 1. Для того чтобы это гарантировать, надо использовать подпрограммы SetLength, SetString или UniqueString;
г) строка не была модифицирована после того, как было сделано приведение типа;
д) все модифицируемые символы принадлежат строке, т.е. указатель не используется для ссылки вне строки.
Те же правила относятся и к смешиванию типов WideString со значениями PWideChar.
{$Q+,R+}
Program StrTest;
{Проверка операций со строками. @Овсянник В.Н., сентябрь 2001}
{$APPTYPE CONSOLE}
uses SysUtils;
var
ShortSGlob : ShortString;
AnsiSGlob : string;
SPChar : PChar;
Procedure TestProc(s1 : ShortString; s2 : string; s3 : PChar;
var s1v : ShortString; var s2v : string; var s3v : PChar);
var
ShortSLoc : ShortString;
AnsiSLoc : string;
Begin
ShortSLoc[3]:='3';
SetLength(AnsiSLoc,5);{без этого оператора программа работает некорректно,
что выражается в пропуске выполняемых операторов}
AnsiSLoc[3]:='3';
WriteLn('ShortSLoc="',ShortSLoc,'"'); {вывод случайных символов,
за исключением '3'}
WriteLn('AnsiSLoc ="',AnsiSLoc,'"'); {#0#0'3'#0#0}
// SPChar:=ShortSLoc; Ошибка: несовместимые типы
// SPChar:=AnsiSLoc; Ошибка: несовместимые типы
// SPChar:=PChar(ShortSLoc); Ошибка: недопустимое приведение типа
AnsiSLoc:=SPChar;
SPChar:=PChar(AnsiSLoc);
WriteLn('SPChar:=PChar(AnsiSLoc); SPChar="',SPChar,'"');{вывод пустой строки }
SPChar:='ABC';
// SPChar:=SPChar+PChar(AnsiSLoc); Ошибка: нельзя применять операцию "+"
End;
BEGIN
TestProc(ShortSGlob,AnsiSGlob,SPChar,ShortSGlob,AnsiSGlob,SPChar);
TestProc(ShortSGlob, PChar(SPChar), SPChar,ShortSGlob,AnsiSGlob,SPChar);
{ TestProc(ShortSGlob,ShortSGlob,
ShortSGlob, Ошибка: несовместимыетипы
ShortSGlob,AnsiSGlob,SPChar);
}
{ TestProc(ShortSGlob,PChar(SPChar),SPChar,ShortSGlob,
PChar(SPChar), Ошибка: типы факт. и форм. п-ров д.б. идентичны
SPChar);
}
ShortSGlob[3]:='3';
SetLength(AnsiSGlob,5);{без этого оператора программа работает некорректно,
что выражается в пропуске выполняемых операторов}
AnsiSGlob[3]:='3';
WriteLn('ShortSGlob="',ShortSGlob,'"');{вывод пустой строки}
WriteLn('AnsiSGlob ="',AnsiSGlob,'"'); {вывод: #0#0'3'#0#$14 - ?}
ReadLn;
END.
«6. Строковые типы данных»
8. Структурные типы