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

Подтипы, которые мы обсуждали в разделе 4.5, определялись добавлением ог­раничения диапазона к дискретному типу (перечисляемому или целочисленно­му). Точно так же подтип массива может быть объявлен добавлением к типу неограниченного массива ограничения индекс'.

type A_Type is array(lnteger range о) of Float;

subtype Line is A_Type(1 ..80);

L, L1, L2: Line;

Значение этого именованного подтипа можно использовать как фактиче­ский параметр, соответствующий формальному параметру исходного неогра­ниченного типа:

Sort(L);

В любом случае неограниченный формальный параметр процедуры Sort ди­намически ограничивается фактическим параметром при каждом вызове процедуры.

Приведенные в разделе 4.5 рассуждения относительно подтипов примени­мы и здесь. Массивы разных подтипов одного и того же типа могут быть при­своены друг другу (при условии, что они имеют одинаковое число элементов), но массивы разных типов не могут быть присвоены друг другу без явного пре­образования типов. Определение именованного подтипа — всего лишь вопрос удобства.

В Ada есть мощные конструкции, называемые сечениями (slices) и сдвигами

(sliding), которые позволяют выполнять присваивания над частями массивов. Оператор

L1(10..15):=L2(20..25);

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

L1(I..J):=L2(l*K..M+2);

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

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) и динамических (как в С).