i21прим/Mod/Strings.odc

MODULE  i21примStrings;
(*  Сначала напоминание:
Целое значение  например, 1  может храниться в переменной любого целого типа  INTEGER, SHORTINT, BYTE, LONGINT. Но если целое слишком большое, то оно может храниться только в достаточно "больших" типах. Например, значение 200 не может храниться в BYTE; для этого значения нужен по меньшей мере SHORTINT.

Аналогично цепочки литер: 
Для цепочки литер нужен ARRAY OF CHAR достаточной длины. Причем длина ARRAY должен быть на единицу больше, чем кол-во литер в цепочке. 
Дело в том, что конец цепочки отмечается спецлитерой 0X (нулевая позиция в кодовой таблице; это значение можно изобразить в программе и как 00Х; именно так его печатает процедура StdLog.Char(...)).
Для ясности: 0X или 00X  это специальное значение, которое может храниться в переменных типа CHAR; на уровне машинного представления это означает, что все биты, составляющие переменную CHAR, равны нулю.

Если a: ARRAY OF CHAR, то обращение к значению  т.е. литерной цепочке  обозначается суффиксом $: a$.

В качестве литер можно брать любые символы таблицы Уникод.

Аналогично можно работать с цепочками SHORTCHAR (расширенный ASCII).
*)
	IMPORT  Log := StdLog;
	
	PROCEDURE Показать* ( comment: ARRAY OF CHAR; IN s: ARRAY OF CHAR );
		VAR  i: INTEGER;
	BEGIN
		Log.String( comment );  Log.Ln;
		Log.String("длина массива: ");  Log.Int( LEN( s ) );  Log.Ln;
		Log.String("длина цепочки литер в массиве: ");  Log.Int( LEN( s$ ) );  Log.Ln; (* кол-во литер до первой спецлитеры 0X *)
				(* сначала напечатаем цепочку: *)
		Log.String("цепочка литер: ");  Log.String( s );  Log.Ln;
		(* теперь все элементы массива по отдельности: *)
		Log.String("все элементы массива: ");  
		FOR  i := 0  TO  LEN( s ) - 1  DO
			Log.Char( s[i] );  Log.Char(' ')
		END;
		Log.Ln;  Log.Ln
	END Показать;
	
	PROCEDURE Демо0*;
		VAR  a: ARRAY 20 OF CHAR;  p: POINTER TO ARRAY OF CHAR;  c: CHAR;
	BEGIN
		(* при входе в процедуру в массиве a хранится "мусор"  какие-то случайные значения: *)
		Показать( "до присваивания мусор:", a );
		(* присвоим значение  цепочку литер: *)
		a := 'Школа "Лидер"';	Показать( "после присваивания:", a );
		(* искусственно "оборвем" цепочку, вставив в ее середину спецлитеру, обозначающую конец; предварительно сохраним заменяемую литеру во вспомогательной переменной c: *)
		c := a[5];
		a[5] := 0X;	Показать( "после обрыва:", a );
		(* восстановим символ: *)
		a[5] := c;	Показать( "восстановили цепочку:", a );
		(* разместим новый массив: *)
		NEW( p, 15 );	
		(* Мы говорили, что при входе в процедуру массивы, объявленные как локальные переменные процедуры, могут хранить "мусор"  случайные значения. Однако массив, размещенный с помощью NEW, сразу после размещения всегда содержит одни нули (числа 0 для массивов целых типов и значения 0X для массивов литер). Это правило Компонентного Паскаля, введенное из соображений безопасности при работе в многопрограммных системах (чтобы нельзя было прочесть данные, оставленные в памяти компьютера другими программами). 
		Убедимся, что в размещенном таким образом массиве хранятся одни нули: *)
		
		Показать( "после размещения с помощью NEW в массиве одни нули:", p );
		
		(* запишем во вновь размещенный массив цепочку литер: *)
		p^ := a$;	Показать( "после присваивания:", p );
		(* после идентификатора нужна шапочка, т.к. мы хотим присвоить что-то не указателю, а той переменной (в данном случае массиву), на которую указатель указывает *)
		p^ := "слишком длинная цепочка вызывает облом" 
	END Демо0;	
	
END  i21примStrings.

Для выполнения примера кликнуть по черному коммандеру:
i21примStrings.Демо0