приведет к тому, что в W будет записано значение 257. Если надо заполнить не всю структуру, а часть ее, то следует указать идентификатор того элемента структуры, начиная с которого надо проводить заполнение. Так, можно заполнить средние элементы массива A:
VAR
А : Array [ 1..500 ] of LongInt;
BEGIN
FillChar( A[ 100 ], 200 * SizeOf( LongInt ), 0 );
...
END.
В этом примере 200 значений типа LongInt массива A, начиная с 100-го, будут заполнены нулем.
С особой осторожностью надо заполнять строки символами, так как нужно заботиться о нулевом байте строки. Подробно об этом говорилось в гл. 8 «Обработка символов и строк».
Кроме того, надо всегда следить за согласованностью реального размера переменной (первого параметра) и длины заполняемого блока (значением NBytes). Если длина блока превышает размер переменной, то будут заполнены байты ОЗУ, следующие за переменной, но к ней уже не относящиеся! Иными словами, если A — статическая переменная или разыменованная ссылка, то следует придерживаться правила
NBytes <= SizeOf( A ).
Сам Турбо Паскаль проверок на корректность параметров не производит.
То, что процедура FillChar заполняет все по байтам, не всегда удобно. В справочном руководстве по Турбо Паскалю приводится пример функции в машинных кодах, заполняющей области памяти так же, как FillChar, но значениями типа Word — по 2 байта сразу (рис. 14.4).
- 301 -
| PROCEDURE FillWord( VAR V; NWords, Fill : Word );
| BEGIN
| inline(
| $C4/$BE/ V / { LES DI, bp+V}
| $8B/$8E/ NWords/ { MOV CX, bp+NWords }
| $8B/$86/ Fill/ {MOV AX, bp+Fill}
| $FC/ { CLD }
| $F3/$AB ) { REP STOSW }
| END;
| VAR
| P : Pointer;
| BEGIN
| P := Ptr( $B800, 0 ); {Начало памяти экрана для цветных мониторов; для монохромных надо задавать P := Ptr( $8000, 0 ) }
| FillWord( Р^, 80*25, 176 + 14 * 256 );
| ReadLn
| END.
Рис. 14.4
На рис. 14.4 дан пример заполнения области экрана (размером 80x25 видимых символов) символом #176 цветом номер 14. Код и цвет скомбинированы в одно значение типа Word. При таком заполнении помните, что первым в машинном представлении слова (Word) идет младший байт, а следом за ним — старший (значение множителя при 256). Обратите внимание на разыменование указателя P, что означает передачу в FillWord адреса начала видеоизображения, а не самого значения P.
14.5. Процедура перемещения данных Move
Процедура Move в некотором роде — уникальная. Она практически не имеет аналогов в стандартах языков высокого уровня. По своей сути она скорее является командой машинного уровня. Процедура содержит три параметра:
Move( VAR Source, Dest; NBytes : Word )
и служит для перемещения в ОЗУ блоков данных размером NBytes. Начало блока задается переменной Source любого типа (первый байт блока соответствует первому байту значения Source). Переменная Dest, точнее задаваемый ею первый байт, указывает на место в
- 302 -
памяти, начиная с которого будет размещен блок. Длина блока должна измеряться в байтах.
Очень эффективно работает процедура Move в различных трюках программистов, таких как копирование области видеопамяти (см. пример к процедуре Keep модуля DOS). Но не менее эффективно ее можно использовать и в более традиционных задачах. Например, копирование массива B в массив A:
А := В;
может быть выполнено процедурой
Move( В, A, SizeOf( В ) );
т.е. блок байтов — значений массива B соответствующего размера — будет скопирован в область памяти, занимаемую массивом A. В этом случае применение Move не дает особого эффекта. Но если, например, нам надо скопировать одну структуру в другую, причем сами структуры — разнотипные, то Move позволяет проделать это максимально просто и с наибольшим быстродействием (рис. 14.5). В этом случае не надо уже беспокоиться об индексах, а надо только указать размер копируемого блока.
| VAR R : RECORD { запись R : } X, Y :Integer; { поля-числа } Arr : Array [ 20..120 ] of Real; { поле-массив } S :String { поле-строка } END; A : Array [ 1..500 J of Real; { массив А } i : Word; BEGIN {Традиционное решение: for i:=20 to 120 do A[ i-19 ] := R.Arr[ i ]; } { Оптимальное решение : } Move( R.Arr, A, SizeOf( R.Arr ) ); END. |
Рис. 14.5
Еще одна область приложения, где Move эффективнее прочих способов — это перемещение значений (сдвиг) внутри одного массива. Пусть, к примеру, объявлен массив
VAR
A : Array[ 1..10000 ] of Real;
- 303 -