Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
3-6-9-12....doc
Скачиваний:
1
Добавлен:
04.08.2019
Размер:
102.91 Кб
Скачать

12 Билет

15 Билет

ShortString, и String[n]

ShortString является частным случаем String[n], а если быть более точным, он полностью эквивалентен String[255].

Если посмотреть на таблицу, где приведены характеристики переменных этого типа, то мы увидим что их размер на один байт больше чем размер хранимой в них строки. Но в данном случае, это не для завершающего символа, как в pChar. Здесь в дополнительном байте хранится текущий размер строки. Кроме того, этот байт располагается не в конце строки, а наоборот, в ее начале. К примеру, если имеется следующее определение:

var s :String[4];

Оно означает, что для переменной s будет статически выделена область памяти размером 5 байт.

Теперь, выполнение оператора s := 'abc', приведёт к тому, что содержимое этих пяти байт станет следующим: байт 1 = 3, байт 2 = 'a', байт 3 = 'b', байт 4 = 'c', а значение байта 5 будет неопределённо – оно будет зависеть от «расклада» в памяти. Т.е., первый символ строки будет находиться во втором байте. Это неудобно, поэтому к символам строк ShortString принято индексироваться, начиная с 1. Следовательно:

s[1] = 'a' – первый символ строки

s[2] = 'b' – второй символ строки

s[3] = 'c' – третий символ строки

s[4] = все что угодно :).

А как же байт длины? Да все очень просто, к нему можно обратиться как s[0]. Только вот есть маленькая проблемка. Поскольку элементами строки являются символы, то и тип значения s[0] тоже будет символ. Т.е., если Вы хотите получить длину строки в виде целого числа, как это принято у нормальных людей, то надо выполнить соответствующее преобразование типа: Ord(s[0]) = 3 – размер строки.

Теперь, я думаю, Вам станет ясно, почему для типа String[n] существует ограничение 0<=n<=255. Это весь набор значений, которые могут быть представлены в одном байте. На всякий случай, отмечу, что размерность переменной (n) определяет размер выделяемой под эту переменную памяти, и он не зависит от размера строки, которая там хранится. Т.е., если, например переменная описана как String[30], то даже если присвоить ей значение 'abcd', то размер этой переменной все равно останется 31 байт. Это иногда бывает очень удобно, например, при записи (чтении) таких переменных в файл (из файла).

В качестве примера работы со структурой хранения такого типа, приведу пример все той же функции возвращающей длину строки:

function StringLength (s :ShortString) :Cardinal;

begin

Result := Ord(s[0]);

end;

Как видите, это код существенно компактнее, и быстрее чем соответствующий код для pChar. Именно поэтому, он и применялся в языке Pascal.

Однако ясно, что ограничения переменных этого типа – максимальный размер строки 255 символов, и всегда максимальный размер занимаемой переменной памяти, вне зависимости от реально помещенной в нее строки, заставили разработчиков Delphi вести новые строковые типы. Вот к ним мы сейчас и перейдем.

AnsiString и WideString

Строки этого типа объединили в себе ряд качеств как строк ShortString и их байтом длины, так и строк завершающихся нулем (pChar). Последнее было необходимо, поскольку к моменту их появления, засилье C-ишников было уже так велико :), что большинство системных функций Windows API оперировало строками именно такого формата. А если серьезно, то такой формат строк хоть и более трудоемок в обработке, зато в принципе лишен ограниченности на максимальный размер строки. Ведь хранение размера строки всегда ограниченно какими-либо рамками: если хранить в байте, то ограничение 255 байт; если хранить в слове, то ограничение 65535 символов; и т.д. Однако, совсем отказываться от хранения текущей длинны строки в Borland не стали. Но об этом позже.

Напомню, что еще одним из недостатков статически размещаемых строк ShortString было "расточительство". Т.е. определив переменную такого типа, мы заранее резервировали под нее 256 байт памяти, поэтому, если мы один раз, во всей программе, присвоили ей значение 'abcd', то 251 байт памяти мы просто «пустили на ветер». Казалось бы, а зачем так определили, написали бы String[4], и ничего не потеряли бы. Но, когда мы пишем программу, мы же чаще всего не знаем что мы будем «класть» в эту переменную. Вот и определяем с запасом. Решением этой проблемы стало использование динамически размещаемых строк.

Нуль-терминальные строки широко используются при обращениях к так называемым API-функциям Windows (API - Application Program Interface - интерфейс прикладных программ). Поскольку компоненты Delphi берут на себя все проблемы связи с API-функциями Windows, программисту редко приходится прибегать к нуль-терминальным строкам. Тем не менее в этом разделе описываются особенности обработки таких строк.

базовый тип string хранит в памяти терминальный нуль, поэтому Object Pascal допускает смешение обоих типов в одном строковом выражении, а также реализует взаимное приведение типов с помощью автофункций преобразования String и PChar. Например:

procedure TfmExample.FormActivate(Sender: TObject);

var

pcS: PChar;

ssS: String;

begin

pcS := '123456';

ssS := 'X = ';

IbOutput.Caption := ssS + pcS;

end;

В строке IbOutput будет выведено х = 123456. Другой пример. В состав API-функцией входят функция MessageBox, с помощью которой на экране создается диалоговое окно с заголовком, текстовым сообщением и набором кнопок. Если в конце предыдущего примера добавить оператор

MessageBox(0, ssS + pcS, 'Заголовок окна', mb_0k);

то компилятор укажет на ошибку, т. к. вторым параметром обращения к функции должно быть выражение типа PChar, в то время как выражение sss+pcs приводится компилятором к общему типу String. Правильным будет такое обращение:

MessageBox(0, PChar (ssS + pcS), 'Заголовок окна', mb_0k) ;

Текстовые константы совместимы с любым строковым типом, поэтому третий параметр обращения (он тоже должен быть типа PChar) компилятор обработает без ошибок.