logo
Языки программирования

5.5. Строковый тип

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

char s[]= "Hello world";

chars[] = {‘H’,’e’,’l’,’o’,’ ‘,’w’,’o’,’r’,’l’,’d’,’/0’};

Затем нужно найти некоторый способ работы с длиной строки. Вышеупо­мянутый пример уже показывает, что компилятор может определить размер I строки без явного его задания программистом. Язык С использует соглаше-I ние о представлении строк, согласно которому первый обнаруженный нуле­вой байт завершает строку. Обработка строк в С обычно содержит цикл while вида:

C

while (s[i++]!='\0')... •

Основной недостаток этого метода состоит в том, что если завершающий ноль почему-либо отсутствует, то память может быть затерта, так же как и при лю­бом выходе за границы массива:

C

char s[11]= "Hello world"; /* He предусмотрено место

для нулевого байта*/

chart[11];

strcpy(t, s); /* Копировать set. Какой длины s? */

Другие недостатки этого метода:

• Строковые операции требуют динамического выделения и освобожде­ния памяти, которые относительно неэффективны.

• Обращения к библиотечным строковым функциям приводят к повтор­ным вычислениям длин строк.

• Нулевой байт не может быть частью строки.

Альтернативное решение, используемое некоторыми диалектами языка Pascal, состоит в том, чтобы включить явный байт длины как неявный нуле­вой символ строки, чья максимальная длина определяется при объявлении:

S:String[10];

Pascal

S := 'Hello world'; (* Требуется 11 байтов *)

writeln(S);

S:='Hello';

writeln(S);

Сначала программа выведет «Hello worl», так как строка будет усечена до объявленной длины. Затем выведет «Hello», поскольку writeln принимает во внимание неявную длину. К сожалению, это решение также небезупречно, потому что возможно непосредственное обращение к скрытому байту длины и затирание памяти:

Pascal


s[0]:=15;

В Ada есть встроенный тип неограниченного массива, называемый String, со следующим определением:

Ada


type String is array(Positive range <>) of Character;

Каждая строка должна быть фиксированной длины и объявлена с индексным ограничением:

Ada

S:String(1..80);

В отличие от языка С, где вся обработка строк выполняется с использованием библиотечных процедур, подобных strcpy, в языке Ada над строками допускаются такие операции, как конкатенация «&», равенство и операции отноше­ния, подобные «<». Поскольку строго предписан контроль соответствия типов, нужно немного потренироваться с атрибутами, чтобы заставить все заработать:

Ada

S1: constant String := "Hello";

S2: constant String := "world";

T: String(1 .. S1 'Length + 1 + S2'Length) := S1 & ' ' & S2;

Put(T); -- Напечатает Hello world

Точная длина Т должна быть вычислена до того, как выполнится присваива­ние! К счастью, Ada поддерживает атрибуты массива и конструкцию для со­здания подмассивов (называемых сечениями — slices), которые позволяют выполнять такие вычисления переносимым способом.

Ada 83 предоставляет базисные средства для определения строк нефикси­рованной длины, но не предлагает необходимых библиотечных подпрограмм для обработки строк. Чтобы улучшить переносимость, в Ada 95 определены стандартные библиотеки для всех трех категорий строк: фиксированных, из­меняемых (как в языке Pascal) и динамических (как в С).