Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Массивы

.pdf
Скачиваний:
39
Добавлен:
03.06.2015
Размер:
241.78 Кб
Скачать

Массивы Массив - структурированный тип данных, состоящий из некоторого числа элементов одного типа.

В Ассемблере массивом можно назвать несколько подряд идущих в памяти байт, слов или двойных слов, но все элементы массива должны быть либо байтами, либо словами, либо двойными словами, т.е. иметь одинаковую длину. В качестве имени массива используется символическое имя адреса (смещения) первого байта первого элемента массива.

Для понимания расположения элементов массива в памяти и обращения к ним необходимо вспомнить основные типы данных микропроцессора и расположение байтов в них (рис 1).

Рис 1.Основные типы данных микропроцессора

Пример описания и определения массива:

- из 5 элементов, размер каждого элемента 4 байта:

mas1 dd 1,2,3,4,5 ;mas –имя массива, dd-тип элементов массива двойное слово

- используя оператор повторения dup:

;массив из 5 нулевых элементов, размер каждого элемента 2 байта: mas2 dw 5 dup (0)

При работе с массивами необходимо четко представлять себе, что все элементы массива располагаются в памяти компьютера последовательно. Только программист с помощью составленного им алгоритма обработки определяет, как нужно трактовать эту последовательность байт, составляющих массив. Так, одну и ту же область памяти можно трактовать как одномерный массив, и одновременно те же самые данные могут трактоваться как двухмерный массив. Все зависит только от алгоритма обработки этих данных в конкретной программе. Сами по себе данные не несут никакой информации о своем “смысловом”, или логическом, типе. Помните об этом принципиальном моменте.

Эти же соображения можно распространить и на индексы элементов массива. Ассемблер не подозревает об их существовании и ему абсолютно все равно, каковы их численные смысловые значения.

Для того чтобы обратиться к элементу массива, к его имени нужно добавить индекс. В языке ассемблера индексы массивов — это обычные

адреса.

Чтобы получить доступ к третьему элементу, нужно к адресу массива mas3 прибавить 6. Нумерация элементов массива в ассемблере начинается с нуля. То есть в нашем случае речь, фактически, идет о 4-м элементе массива — 7, но об этом знает только программист; микропроцессору в данном случае все равно — ему нужен только адрес.

Архитектура микропроцессора предоставляет достаточно удобные программно-аппаратные средства для работы с массивами. К ним относятся базовые и индексные регистры, позволяющие реализовать несколько режимов адресации данных. Используя данные режимы адресации, можно организовать эффективную работу с массивами в памяти. Вспомним эти режимы: индексная адресация со смещением — режим адресации, при котором эффективный адрес (т.е. смещение данных относительно начала сегмента данных) формируется из двух компонентов:

o постоянного (базового) — указанием прямого адреса массива в виде имени идентификатора, обозначающего начало массива; o переменного (индексного) — указанием имени индексного регистра.

Пример обращения к элементам массива:

mas3

dw

0,5,6,7,8,9 ;определили одномерный массив с размерностью элементов в слово (2 байта)

...

 

 

mov

si,4

;поместить в регистр SI индекс 4 для обращения к третьему элементу массива

;поместить 3-й элемент массива mas в регистр АХ:

mov

ax,mas[si]

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

база + (индекс*размер элемента).

Микропроцессор позволяет масштабировать индекс. Это означает, что если указать после имени индексного регистра знак умножения “*” с последующей цифрой 2, 4 или 8, то содержимое индексного регистра будет умножаться на 2, 4 или 8, то есть масштабироваться. Применение масштабирования облегчает работу с массивами, которые имеют размер элементов, равный 2, 4 или 8 байт, так как микропроцессор сам производит коррекцию индекса для получения адреса очередного элемента массива. Нам нужно лишь загрузить в индексный регистр значение требуемого индекса (считая от 0).

Возможность масштабирования появилась в микропроцессорах Intel, начиная с модели i486. По этой причине в программах необходимо писать директиву

.486.

Пример использования масштабирования:

 

;просмотр элементов массива

 

mas

dw

2,7,0,0,1,9,3,6,0,8

;исходный массив

 

 

 

mov

cx,10

;значение счетчика цикла в cx

mov

esi,0

;индекс в esi

 

see:

 

 

 

mov

dx,mas[esi*2];первый элемент массива в dx

inc

esi

;на следующий элемент

loop see

 

 

 

Упражнение 1.

 

 

 

 

Упражнение 2.

 

 

 

 

 

Использование цикла для инициализации значениями области памяти,

Просмотр массива, состоящего из слов, и сравнение его элементов с

которую можно будет впоследствии трактовать как массив.

нулем. Выводится соответствующее сообщение.

TITLE Инициализация массива из 10 элементов внутри программы числами

.686

 

 

 

 

 

 

option casemap:none

 

 

 

;0 1 2 3 4 5 6 7 8 9

 

 

 

 

 

 

 

 

 

.686

 

 

 

 

 

include \masm32\include\masm32rt.inc

 

 

option casemap:none

 

 

 

.data

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

include \masm32\include\masm32rt.inc

 

ConsoleTitle db 'Concole input-output ',0

;наименования консоли

 

 

 

 

 

 

msg_1

db

' not equality 0!', 0ah, 0dh,0

 

;сообщение если элемент

.data

 

 

 

 

 

 

 

 

 

 

 

;массива "не равен нулю"

ConsoleTitle db 'Concole input-output ',0

;определение строки для

msg_2

db

 

' equality 0!', 0ah, 0dh,0

;сообщение если елемент

 

 

 

 

 

;наименования консоли

 

 

 

 

 

 

;массива "равен нулю"

msg db 'Result massive :',0ah, 0dh, 0 ; комментарий к выводимому массиву

msg_3

db

 

0ah, 0dh, 'Element ',0

 

;сообщение: "Элемент"

mas db 10 dup (?)

 

 

;исходный массив (неинициализированный)

mas

dw

 

2,7,0,0,1,9,3,6,0,8

 

;исходный массив

i db 0

 

 

;переменная для инициализации массива

format db '%d',0 ;формат выводимых целых чисел (для invoke crt_printf)

format db '%d',0

;формат выводимых целых чисел (для invoke crt_printf)

 

 

 

 

 

 

 

format_c db '%c',0

 

;формат для вывода символов (для invoke crt_printf)

.code

 

 

 

 

 

 

 

 

 

 

 

 

main:

 

 

 

 

 

 

.code

 

 

 

 

 

invoke SetConsoleTitle, addr ConsoleTitle

 

;вывод имени консоли

main:

 

 

 

 

 

xor eax,eax

 

 

 

 

 

invoke SetConsoleTitle, addr ConsoleTitle

;вывод имени консоли

 

;обнуление eax

 

 

 

 

 

 

 

 

prepare:

 

 

 

 

 

 

xor eax,eax

 

;обнуление eax

 

mov

 

ecx,10

;значение счетчика цикла в ecx

 

mov ecx,10

 

;значение счетчика цикла в ecx

 

mov

 

esi,0

;индекс в esi

 

mov esi,0

 

 

;индекс начального элемента в esi

compare:

 

 

 

 

 

go:

 

 

;цикл инициализации

 

mov

 

dx,mas[esi*2] ;первый элемент массива в dx

 

mov bh,i

 

;i в bh

 

 

 

cmp

 

dx,0

;сравнение dx c 0

 

mov mas[esi],bh

;запись в массив значения i

 

je

 

equal

;переход, если равно 0

 

inc i

 

 

;инкремент i (i=i+1)

not_equal:

 

 

;не равно 0

 

 

 

inc esi

;продвижение к следующему элементу массива

 

push ecx

 

;сохранить значение ECX в стеке

 

loop go

;повторить цикл

 

invoke crt_printf, addr msg_3

;вывод сообщения msg_3

 

 

 

 

 

 

invoke

crt_printf, addr format, esi ;вывод номера элемента массива на экран

;вывод на экран получившегося массива

 

invoke crt_printf, addr msg_1

;вывод сообщения msg_1

invoke crt_printf, addr msg

;Сообщение о выводе массива

 

pop ecx

 

;восстановление из стека значения ECX

mov

ecx,10

 

 

;значение счетчика цикла в ECX

 

inc

 

esi

;на следующий элемент

mov

esi,0

 

 

;присвоение индексному регистру значения 0

 

dec

 

ecx

;условие для выхода из цикла

show:

 

 

;цикл вывода на экран получившегося массива

 

jecxz

exit_

;ecx=0? Если да — на выход

xor edx,edx

 

 

 

 

 

jmp

 

compare ;нет — повторить цикл

mov dl,mas[esi]

 

 

;значение элемента массива

equal:

 

 

 

;равно 0

 

 

push ecx

 

;сохранение значения регистра ECX в стеке

push ecx

 

 

 

 

 

invoke crt_printf, addr format, edx ;вывод очередного элемента массива

invoke crt_printf, addr msg_3

;вывод сообщения msg_3

invoke

crt_printf, addr format_c,' ' ;вывод пробела между выводимыми

invoke

crt_printf, addr format, esi ;вывод номера элемента массива на экран

pop ecx

 

 

 

;элем. массива

invoke crt_printf, addr msg_2

;вывод сообщения msg_2

;возвращение сохраненного значения регистра ECX из стека

 

pop ecx

 

 

 

 

inc esi

 

 

 

 

 

 

inc

 

esi

;на следующий элемент

loop show

 

;повторить цикл

 

dec

 

ecx

;все элементы обработаны?

invoke Sleep, INFINITE ;задержка закрытия консоли для просмотра результатов

 

jecxz

exit_

 

 

 

 

jmp

 

compare

 

 

 

invoke ExitProcess,0

 

;передача управления Windows

exit_:

 

 

 

 

 

 

end main

 

 

;конец программы

invoke Sleep, INFINITE ;задержка закрытия консоли для просмотра результатов

Результат работы программы:

 

invoke ExitProcess,0

 

;передача управления Windows

 

end main

 

 

;конец программы

Result massive :

 

 

 

 

Ррезультат работы программы:

 

 

0 1 2 3 4 5 6 7 8 9

 

 

 

 

Element 0 not equality 0!

 

 

 

Задание 1. Инициализируйте область памяти числами 9,8,7,6,5,4,3,2,1,0

Element 1 not equality 0!

 

 

 

Element 2 not equality 0!

 

 

 

 

 

 

 

 

 

Element 3 equality 0!

 

 

 

 

 

 

 

 

 

 

Element 4 equality 0!

 

 

 

 

 

 

 

 

 

 

Element 5 equality 0!

 

 

 

 

 

 

 

 

 

 

Element 6 equality 0!

 

 

 

 

 

 

 

 

 

 

Element 7 not equality 0!

 

 

 

 

 

 

 

 

 

Element 8 not equality 0!

 

 

 

 

 

 

 

 

 

Element 9 not equality 0!

 

 

 

 

 

 

 

 

 

Задание 2. Программа выводит неверный результат. Исправьте код

 

 

 

 

 

 

программы, чтобы она выдавала корректный результат.

Масштабирование эффективно лишь тогда, когда размерность элементов

Упражнение 4.

Ввод и вывод элементов массива в консоли

массива равна 2, 4 или 8 байт. Если же размерность элементов другая, то

TITLE Ввод размерности массива

 

 

организовывать обращение к элементам массива нужно обычным способом,

TITLE Ввод элементов массива через пробел

как описано ранее.

 

 

 

 

TITLE Удвоение элементов массива

 

 

Рассмотрим пример работы с массивом из пяти трехбайтовых элементов.

TITLE Вывод элементов массива

 

 

Младший байт в каждом из этих элементов представляет собой некий

.686

 

 

 

 

 

 

счетчик, а старшие два байта — что-то еще, для нас не имеющее никакого

option casemap:none

 

 

 

значения. Необходимо последовательно обработать элементы данного

 

 

 

 

 

 

 

массива, увеличив значения счетчиков на единицу.

include \masm32\include\masm32rt.inc

 

 

Упражнение 3. Обработка массива элементов с нечетной длиной

.data

 

 

 

 

 

 

.686

 

 

 

 

 

ConsoleTitle db 'Concole input-output ',0

;наименования консоли

option casemap:none

 

 

 

msg_1 db 'Input elements array: ',0 ;сообщение о вводе элементов массива

 

 

 

 

 

 

msg_2 db 'Input number elements array n=: ',0 ;сообщение о вводе кол-ва

include \masm32\include\masm32rt.inc

 

msg_3 db 'Result array: ',0

 

 

;элем. массива

 

 

 

 

 

 

;сообщение о результативном массиве

.data

 

 

 

 

 

msg_4 db ' ',0 ;переменная содержащая ASCII код пробела

ConsoleTitle db 'Concole input-output ',0 ;наименования консоли

N=5

;количество элементов массива

mas db 5 dup (3 dup (0))

;исходный массив из 5-и элем. по 3 байта в

 

;каждом и во всех 15 байтов записано число 0

msg db ' ',0

msg_1 db 'Byte counter: ',0 ;сообщение: Байт-счетчик

format db '%d',0

;формат выводимых целых чисел (для invoke crt_printf)

.code

 

 

 

 

 

main:

 

 

 

 

 

invoke SetConsoleTitle, addr ConsoleTitle

;вывод имени консоли

xor eax,eax

 

;обнуление eax

 

 

mov

 

esi,0

 

;0 в esi

 

mov

 

ecx,N

;N в ecx

go:

 

 

 

 

 

xor edx,edx

 

;обнуление edx

 

mov

dl,mas[esi]

;первый байт поля в dl

inc

dl

;увеличение dl на 1 (по условию)

mov

mas[esi],dl

;заслать обратно в массив

add

esi,3

 

;сдвиг на следующий элемент массива

loop

go

 

;повтор цикла

 

invoke crt_printf, addr msg_1

 

 

mov

esi,0 ;подготовка к выводу на экран элементов массива

 

 

;содержащие байт-счетчик

mov

ecx,N

 

 

 

show:

;вывод на экран содержимого первых байт полей

xor edx,edx

 

 

 

 

mov dl,mas[esi]

;1-й байт для вывода, затем 3, 6, 9 и 12

push ecx

 

 

 

 

invoke

crt_printf, addr format, edx

 

 

invoke crt_printf, addr msg ; вывод пробела между выводимыми элементами add esi,3

pop ecx loop show

exit_:

invoke Sleep, INFINITE invoke ExitProcess,0 end main

Результат работы программы:

Byte counter: 1 1 1 1 1

mas dd 128 dup (?) ;исходный массив с неопределенными элементами

x_mas dd ?

;переменная для хранения одного введенного элемента

массива

 

 

 

 

n dd ?

;кол-во элементов массива

 

formats db '%d',0

;формат вводимых и выводимых целых чисел

.code

 

 

 

 

main:

 

 

 

 

invoke SetConsoleTitle, addr ConsoleTitle

;вывод имени консоли

invoke crt_printf, addr msg_2

 

;вывод сообщения о вводе n

invoke crt_scanf, ADDR formats, ADDR n

;ввод n

invoke crt_printf, addr msg_1

;вывод сообщения о вводе элем. массива

mov esi,0 mov ecx,n m1:

push ecx

invoke crt_scanf,ADDR formats,ADDR x_mas ;ввод x_mas как символьной

;строки и преобр. ее в число, с помещ. в яч. x_mas mov eax,x_mas ;1-й, 2-й и т.д. введенный элемент поместить в EAX

mov mas[esi*4],eax ;1-й, 2-й и т.д. введенные элем. в mas[0], mas[1], и т д. inc esi ;продвижение к вводу следующего элемента массива

pop ecx

loop m1 ;повторить цикл ввода элементов массива

;вывод на экран получившегося массива

invoke crt_printf, addr msg_3

;сообщение о выводе массива

mov

ecx,n

 

;значение счетчика цикла в ECX

mov

esi,0

 

;присвоение индексному регистру значения 0

show:

 

;цикл вывода на экран получившегося массива

xor edx,edx

imul eax,mas[esi*4],2 ;удвоение элементов массива командой

mov edx,eax

;целочисленного умножения со знаком

;значение элемента массива в EDX

push ecx

;сохранение значения регистра ECX в стеке

invoke crt_printf, addr formats, edx ;вывод очередного элемента массива invoke crt_printf, addr msg_4 ;вывод пробела между выводимыми элем. массива

pop ecx

;возвращение сохраненного значения регистра ECX из стека

inc esi

 

loop show

;повторить цикл

invoke Sleep, INFINITE ;задержка закрытия консоли invoke ExitProcess,0

end main

Результат работы программы:

Input number elements array n=: 5 Input elements array: 0 -23 5 7 -4 Result array: 0 -46 10 14 -8

Задача 1. Сложить соответствующие элементы двух массивов, результат вывести на экран.

masx

dw

2,1,2,1,2,1,2,1,2,1

masy

dw

1,2,1,2,1,2,1,2,1,2