390 / 323 / 19 Регистрация: 26.05.2009 Сообщений: 2,696 |
|
1 |
|
В массиве найти минимальный и максимальный элемент11.09.2012, 02:25. Показов 54441. Ответов 22
Здравствуйте! На ассемблере последний раз писал что-то ещё на 1-м курсе универа и всё забыл за неимением практики. А тут пришла знакомая и попросила помочь с заданием. Добавлено через 8 минут
0 |
Troll_Face 608 / 406 / 8 Регистрация: 26.04.2012 Сообщений: 2,065 |
||||||||
12.09.2012, 19:34 |
2 |
|||||||
не тестировал, сразу говорю, но вроде так… Добавлено через 22 часа 34 минуты
3 |
390 / 323 / 19 Регистрация: 26.05.2009 Сообщений: 2,696 |
|
12.09.2012, 21:42 [ТС] |
3 |
И не понимаю, что делает «lodsb». Можете пояснить, для чего эта команда в этом коде?
0 |
390 / 323 / 19 Регистрация: 26.05.2009 Сообщений: 2,696 |
|
12.09.2012, 21:57 [ТС] |
4 |
Вот что у меня получается: Миниатюры
0 |
390 / 323 / 19 Регистрация: 26.05.2009 Сообщений: 2,696 |
|
12.09.2012, 22:11 [ТС] |
5 |
В архиве то, что я написал. Запускаю по run.bat.
0 |
766 / 310 / 11 Регистрация: 27.05.2011 Сообщений: 703 |
|
12.09.2012, 22:14 |
6 |
body90, ты наверно думаешь, что представленный код является полным?
2 |
body90 390 / 323 / 19 Регистрация: 26.05.2009 Сообщений: 2,696 |
||||
12.09.2012, 22:25 [ТС] |
7 |
|||
Написал так. Компиллируется без ошибок, но вот когда запускаю *.exe — выскакивает ошибка с кнопкой «Закрыть». Я что-то неправильно сделал?
только вот ещё одно, результата на экране ты не увидишь, пока не допишешь вывод, либо ч/з отладчик.. А как вывод делать?
0 |
766 / 310 / 11 Регистрация: 27.05.2011 Сообщений: 703 |
|
12.09.2012, 22:28 |
8 |
ну у тебя часть кода находится в данных, перенести надо..
1 |
body90 390 / 323 / 19 Регистрация: 26.05.2009 Сообщений: 2,696 |
||||
13.09.2012, 02:16 [ТС] |
9 |
|||
.data должен быть пустым? Добавлено через 36 минут
Добавлено через 25 минут
0 |
390 / 323 / 19 Регистрация: 26.05.2009 Сообщений: 2,696 |
|
13.09.2012, 02:49 [ТС] |
10 |
Вот как оно вылетает (первое изображение) после нажатия F9 в TLINK.exe. Миниатюры
0 |
390 / 323 / 19 Регистрация: 26.05.2009 Сообщений: 2,696 |
|
13.09.2012, 05:31 [ТС] |
11 |
Почему-то мне кажется, что приложение просто зацикливается. Добавлено через 2 часа 18 минут
0 |
Ушел с форума 15883 / 7459 / 1010 Регистрация: 11.11.2010 Сообщений: 13,442 |
|
13.09.2012, 05:47 |
12 |
body90, опять используется массив двойных слов вместо массива байтов, и массив array убери из секции code в секцию data
1 |
body90 390 / 323 / 19 Регистрация: 26.05.2009 Сообщений: 2,696 |
||||||||
13.09.2012, 11:08 [ТС] |
13 |
|||||||
Mikl___, сделал так, как Вы сказали. Совсем теперь по «циклу» один раз стало проходить.
Добавлено через 21 минуту
хотя обращений к ним нет. Может я чего-то не понимаю. Добавлено через 25 секунд
0 |
Ушел с форума 15883 / 7459 / 1010 Регистрация: 11.11.2010 Сообщений: 13,442 |
|
13.09.2012, 11:40 |
14 |
body90, тебе же сказали — помести array в сегмент данных!
1 |
body90 390 / 323 / 19 Регистрация: 26.05.2009 Сообщений: 2,696 |
||||||||
13.09.2012, 11:46 [ТС] |
15 |
|||||||
Всё равно результат тот же.
В момент до выполнения строки
bh = 32
1 |
390 / 323 / 19 Регистрация: 26.05.2009 Сообщений: 2,696 |
|
13.09.2012, 11:47 [ТС] |
16 |
Вот скрин. Миниатюры
1 |
Mikl___ Ушел с форума 15883 / 7459 / 1010 Регистрация: 11.11.2010 Сообщений: 13,442 |
||||
13.09.2012, 11:50 |
17 |
|||
должно быть вот так
2 |
390 / 323 / 19 Регистрация: 26.05.2009 Сообщений: 2,696 |
|
13.09.2012, 11:56 [ТС] |
18 |
bh работает, а в bl теперь всё время лежит 0, хотя в массиве минимальный элемент = 2.
0 |
Ушел с форума 15883 / 7459 / 1010 Регистрация: 11.11.2010 Сообщений: 13,442 |
|
13.09.2012, 12:03 |
19 |
body90, естественно, потому что изначально BL=0, а ноль всегда меньше двух
1 |
body90 390 / 323 / 19 Регистрация: 26.05.2009 Сообщений: 2,696 |
||||
13.09.2012, 12:03 [ТС] |
20 |
|||
Не знаю правильно ли, но вышел из ситуации так:
0 |
Есть задание. Необходимо найти значение максимального элемента в массиве. Элементы массива должны иметь тип WORD
(2 байта). В первом элементе массива должно хранить количество элементов массива −1. То есть оттуда мы должны считать количество чисел, перейти на адрес второй ячейки массива, и начиная с числа по этому адресу уже сравнивать.
Написал следующий код:
section .text
global _start
_start:
mov eax, 3 ; mov eax, [x]
mov ebx,0 ; EBX будет хранить максимальное значение
mov ecx, x ; ECX будет указывать на текущий элемент для выполнения операции сравнения
add ecx, 2
top: cmp ebx, [ecx]
JNS l1
mov ebx, [ecx]
l1: add ecx, 2 ; перемещаем указатель на следующий элемент
dec eax ; выполняем декремент счётчика
jnz top ; если счётчиком не является 0, то тогда выполняем цикл ещё раз
done:
add ebx, '0'
mov [max], ebx ; готово, сохраняем результат в переменной sum
display:
mov edx, 2 ; длина сообщения
mov ecx, max ; сообщение для написания
mov ebx, 1 ; файловый дескриптор (stdout)
mov eax, 4 ; номер системного вызова (sys_write)
int 0x80 ; вызов ядра
mov eax, 1 ; номер системного вызова (sys_exit)
int 0x80 ; вызов ядра
section .data
global x
x:
dw 3
dw 2
dw 4
dw 3
max:
dw 0
Компилирую в Linux через консоль, компиляция проходит, но результат выводит неправильный. Кроме того, ему не нравится синтаксис(segmentation fault)
mov eax, [x]
Если кто разбирается в ассемблере, помогите, пожалуйста. Где я ошибся?
Improve Article
Save Article
Like Article
Improve Article
Save Article
Like Article
Problem – Determine largest number in an array of n elements. Value of n is stored at address 2050 and array starts from address 2051. Result is stored at address 3050. Starting address of program is taken as 2000.
Example:
Algorithm:
- We are taking first element of array in A
- Comparing A with other elements of array, if A is smaller then store that element in A otherwise compare with next element
- The value of A is the answer
Program:
Memory Address | Mnemonics | Comment |
---|---|---|
2000 | LXI H 2050 | H←20, L←50 |
2003 | MOV C, M | C←M |
2004 | DCR C | C←C-01 |
2005 | INX H | HL←HL+0001 |
2006 | MOV A, M | A←M |
2007 | INX H | HL←HL+0001 |
2008 | CMP M | A-M |
2009 | JNC 200D | If Carry Flag=0, goto 200D |
200C | MOV A, M | A←M |
200D | DCR C | C←C-1 |
200E | JNZ 2007 | If Zero Flag=0, goto 2007 |
2011 | STA 3050 | A→3050 |
2014 | HLT |
Explanation:
Registers used: A, H, L, C
- LXI 2050 assigns 20 to H and 50 to L
- MOV C, M copies content of memory (specified by HL register pair) to C (this is used as a counter)
- DCR C decrements value of C by 1
- INX H increases value of HL by 1. This is done to visit next memory location
- MOV A, M copies content of memory (specified by HL register pair) to A
- INX H increases value of HL by 1. This is done to visit next memory location
- CMP M compares A and M by subtracting M from A. Carry flag and sign flag becomes set if A-M is negative
- JNC 200D jumps program counter to 200D if carry flag = 0
- MOV A, M copies content of memory (specified by HL register pair) to A
- DCR C decrements value of C by 1
- JNZ 2007 jumps program counter to 2007 if zero flag = 0
- STA 3050 stores value of A at 3050 memory location
- HLT stops executing the program and halts any further execution
Advantages of finding the largest number in an array:
- It is a simple and straightforward task that can be easily implemented in any programming language.
- It is a common operation used in many algorithms and applications, such as finding the maximum value in a data set or determining the winner of a game.
- It is a fast operation that can be completed in O(n) time complexity, where n is the number of elements in the array.
Disadvantages of finding the largest number in an array:
- If the array is unsorted, finding the largest number requires iterating through the entire array, which can be inefficient for very large arrays.
- If multiple elements in the array have the same maximum value, finding only one of them requires additional logic or iterations, which can add complexity to the algorithm.
- If the array is very large and memory is limited, storing the entire array in memory may not be feasible, which could require a more complex solution such as sorting the array in smaller parts.
Last Updated :
07 May, 2023
Like Article
Save Article
У меня задание, где нужно ввести массив и вывести его на экран. Но теперь пеподу понадобилось, чтоб еще найти максимальный элемент и заменить его на 1 и вывести на экран массив с замененным элементом. Я ввод/вывод еле сделал (и то не без дорых людей). Я как найти и заменить вообще не знаю.
Все время с++ изучали, а тут вот и ассемблер теперь нужно.
Помогите пожалуйста, если можете.
MODEL SMALL ;Малая модель памяти cs<>ds,cs<>ss
STACK 100h ;100h памяти под сегмент
LOCALS @@ ;Метки с префиксом @@ счит. локальными
mSize equ 3 ;Размер матрицы
;—————————————————
; Сегмент данных
;—————————————————
data segment ;Начало сегмента данных
matrix db mSize*mSize dup(?)
prompt2 db ‘Массив:’,’$’ ;DOS-строка ‘числа…’
prompt3 db ‘Введите число:’,’$’ ;DOS-строка ‘введите…’
endl db 13,10,’$’ ;DOS-строка — перевод на след. строчку
nbSize db ? ;Заголовок под буфер ввода
nbInp db ?
buf db 6 dup(?) ;DOS-строка буфер для числа
db ‘$’
data ends ;Конец сегмента данных
;—————————————————
; Сегмент кода
;—————————————————
code segment ;Начало сегмента
assume cs:code,ds:data ;Обещаем выставить cs=code,ds=data
start: ;Точка входа в программу
mov ax,data ;ds=data (Инициализируем DS сегмент)
mov ds,ax
mov cx,mSize*mSize ;cx=кол-ву эл-тов матрицы
mov si,OFFSET matrix ;ds:si указывает на матрицу
call doEnterMatrix ;Вызываем процедуру заполнения матрицы
call doClearScreen ;Очищаем экран
mov si,OFFSET matrix ;ds:si указывает на матрицу
mov cx,mSize*mSize ;cx = кол-ву элементов в матрице
;Вызываем вывод перевода строки
mov si,OFFSET prompt2 ;ds:si указывает на prompt2
call doPrintStr ;Печатаем на экране строку prompt2
mov cx,mSize*mSize ;cx = кол-ву элементов в матрице
mov si,OFFSET matrix ;ds:si теперь указывает на матрицу
call doOut ;Вызываем вывод матрицы
mov si,OFFSET endl ;ds:si указывает на симв. перев. строки
call doPrintStr ;Вызываем вывод перевода строки
call doWaitAKey ;Ожидаем нажатие клавиши
mov ax,4C00h ;Выходим из программы —
int 21h ; прерывание 21h(DOS),ф-я 4Ch
;—————————————————
; doEnterMatrix — процедура ввода
;—————————————————
;
doEnterMatrix proc near ;Начало описания процедуры
push es ;Сохраняем es в стеке
push di ;Сохраняем di в стеке
push si ;Сохраняем si в стеке
push cx ;Сохраняем cx в стеке
push ax ;Сохраняем ax в стеке
pushf ;Сохраняем флаги в стеке
mov byte ptr ds:[nbSize],5 ;Макс. кол-во символов, кот.можно ввести
mov ax,ds ;ax=ds
mov es,ax ;es=ax=ds
mov di,si ;si=di
cld ;Сбрасываем флаг направления (вперёд)
@@lAgain: ;Начало цикла
call doClearScreen ;Вызываем очистку экрана
mov si,OFFSET prompt3 ;ds:si указывает на строку prompt3
call doPrintStr ;Вызываем проц. вывода строки на экран
mov ah,0Ah ;ah=0Ah
mov dx,OFFSET nbSize ;ds:dx указывает на буфер для ввода
int 21h ;Прерывание 21h(DOS) ввод строки
push cx ;Сохраняем cx в стеке
xor ch,ch ;ch=0 (быстрое обнуление)
mov cl,byte ptr ds:[nbInp] ;cl=кол-ву введённых символов
mov si,OFFSET buf ;ds:si указывает на буфер ввода
call doStr2Byte ;Вызвать преобразование строки в число
pop cx ;Восстановить cx из стека
cld ;Сбрасываем флаг направления(вперёд)
stosb ;Сохраняем полученное число в матрицу
loop @@lAgain ;Конец цикла
popf ;Восстанавливаем флаги из стека
pop ax ;Восстанавливаем ax из стека
pop cx ;Восстанавливаем cx из стека
pop si ;Восстанавливаем si из стека
pop di ;Восстанавливаем di из стека
pop es ;Восстанавливаем es из стека
ret ;Выходим из процедуры
doEnterMatrix endp ;Конец описания процедуры
;—————————————————
; doEnterMatrix — процедура вывода
;—————————————————
doOut proc near ;Начало описания процедуры
push si ;Сохраняем si в стеке
push dx ;Сохраняем dx в стеке
push cx ;Сохраняем cx в стеке
push bx ;Сохраняем bx в стеке
push ax ;Сохраняем ax в стеке
pushf ;Сохраняем флаги в стеке
xor ah,ah ;ah=0 (верхняя часть ax)
cld ;Сбрасываем флаг направления (вперёд)
@@lNext: ;Начало цикла
lodsb ;al=следующему эл-ту матрицы
mov bx,si ;Сохраняем si в bx (bx=si)
mov dx,cx ;Сохраняем cx в dx (dx=cx)
mov cx,LENGTH buf ;cx = размеру буфера
mov si,OFFSET buf ;ds:si указывает на начало буфера
call doWord2Str ;Вызываем преобразование числа в строку
mov cx,dx ;Восстанавливаем cx из dx (cx=dx)
mov si,OFFSET buf ;ds:si указывает на буфер (строку)
call doPrintStr ;Выводим буфер (строку)(число)
mov si,bx ;Восстанавливаем si из bx (si=bx)
@@lSkip: ;Метка @@lSkip
loop @@lNext ;Конец цикла
popf ;Восстанавливаем из стека флаги
pop ax ;Восстанавливаем из стека ax
pop bx ;Восстанавливаем из стека bx
pop cx ;Восстанавливаем из стека cx
pop dx ;Восстанавливаем из стека dx
pop si ;Восстанавливаем из стека si
ret ;Выходим из процедуры
doOut endp ;Конец описания процедуры
;—————————————————
; doClearScreen — процедура очистки экрана
;—————————————————
doClearScreen proc near ;Начало описания процедуры
push ax ;Сохраняем ax в стеке
pushf ;Сохраняем флаги
mov ax,0003h ;ah = 0, al = 03 (номер видео режима)
int 10h ;Прерыване 10h(BIOS) устан. вид.режима
popf ;Восстанавливаем из стека флаги
pop ax ;Восстанавливаем из стека ax
ret ;Выходим из процедуры
doClearScreen endp ;Конец описания процедуры
;—————————————————
; doWaitAKey — процедура ожидания клавиши
;—————————————————
doWaitAKey proc near ;Начало описания процедуры
push ax ;Сохраняем ax в стеке
pushf ;Сохраняем флаги в стеке
xor ah,ah ;ah=0 (быстрое обнуление)
int 16h ;Прерывание 16h(BIOS) читаем клавишу
popf ;Восстанавливаем из стека флаги
pop ax ;Восстанавливаем из стека ax
doWaitAKey endp ;Конец описания процедуры
;—————————————————
; doPrintStr — Вывод DOS строки на экран
;—————————————————
doPrintStr proc near ;Начало описания процедуры
push dx ;Сохраняем dx в стеке
push ax ;Сохраняем ax в стеке
pushf ;Сохраняем флаги в стеке
mov ah,09h ;ah = 09h
mov dx,si ;dx = si
int 21h ;Прерывание 21h(DOS) выв. строки
popf ;Восстанавливаем из стека флаги
pop ax ;Восстанавливаем из стека ax
pop dx ;Восстанавливаем из стека dx
ret ;Выходим из процедуры
doPrintStr endp ;Конец описания процедуры
;—————————————————
; doWord2Str — Перевод числа в строку
;—————————————————
doWord2Str proc near ;Начало описания процедуры
push si ;Сохраняем si в стеке
push dx ;Сохраняем dx в стеке
push cx ;Сохраняем cx в стеке
push bx ;Сохраняем bx в стеке
push ax ;Сохраняем ax в стеке
pushf ;Сохраняем в стеке флаги
mov dl,al ;Сохраняем al в dl (dl=al)
mov al,’ ‘ ;al = пробелу
call doFillBuf ;Заполняем буфер пробелами
mov al,dl ;Восстанавливаем al (al=dl)
test ah,10000000b ;ax<0? (первый бит установлен?)
jz @@skipNeg ;Нет => @@skipNeg
neg ax ;ax=-ax
mov byte ptr ds:[si],’-‘ ;Записываем в буфер симв. ‘-‘
@@skipNeg:
dec cx ;Уменьшаем cx (место под знак)
add si,cx ;ds:si указывает на конец буфера
mov bx,10 ;bx=10 (будем делить на 10)
@@lNext: ;Начало цикла
xor dx,dx ;Обнуляем остаток от деления (dx=0)
div bx ;Делим ax на bx (ax=ax/10, dx=остаток)
add dl,’0′ ;Прибавляем к dl символ ‘0’
mov byte ptr ds:[si],dl ;Сохраняем в буфере
test ax,ax ;ax = 0? (делить имеет смысл?)
jz @@lExit ;нет => выход из цикла
dec si ;Сдвигаемся по буферу
loop @@lNext ;Следующий шаг
@@lExit:
popf ;Восстанавливаем из стека флаги
pop ax ;Восстанавливаем из стека ax
pop bx ;Восстанавливаем из стека bx
pop cx ;Восстанавливаем из стека cx
pop dx ;Восстанавливаем из стека dx
pop si ;Восстанавливаем из стека si
ret ;Выходим из процедуры
doWord2Str endp ;Конец описания процедуры
;—————————————————
; doStr2Byte — Перевод строки в байт
;—————————————————
doStr2Byte proc near ;Начало описания процедуры
push si ;Сохраняем si в стеке
push dx ;Сохраняем dx в стеке
push cx ;Сохраняем cx в стеке
push bx ;Сохраняем bx в стеке
mov bx,cx ;Сохраняем cx в bx
cld ;Сбрасываем флаг направления(вперёд)
lodsb ;Читаем первый символ
cmp al,’-‘ ;Сравниваем его с символом ‘-‘
jne @@lSkip ;Если не равен => lSkip
dec cx ;Иначе уменьшаем счётчик символов
dec bx ;И сохранённый тоже
@@lNext: ;Начало цикла (проверка строки)
lodsb ;Загружаем следующий символ в al
@@lSkip:
cmp al,’0′ ;Сравниваем его с ‘0’
jb @@lExitE ;Если меньше,то выходим из цикла(ошибка)
cmp al,’9′ ;Сравниваем его с ‘9’
ja @@lExitE ;Если больше,то выходим из цикла(ошибка)
loop @@lNext ;Конец цикла
dec si ;Передвигаем si на последний символ
mov cx,bx ;Восстанавливаем cx из bx
std ;Устанавливаем флаг переноса (назад)
mov dx,0A01h ;dh=10, dl=1 (коэфф.умножения, множит.)
xor bx,bx ;bx=0 (сумма — быстрое обнуление)
@@lNextD: ;Начало цикла
lodsb ;Считываем предыдущий символ
sub al,’0′ ;Преобразуем символ в число
mul dl ;Умножаем его на dl (1,10,100…)
test ah,ah ;Проверяем вышел ли он за пределы байта
jnz @@lExitE ;Если вышел — выходим из цикла (ошибка)
add bx,ax ;bx=bx+ax (суммируем)
mov al,dl ;al=dl (готовимся к умножению множителя=)
mul dh ;умножаем
mov dl,al ;dl=множителю (1,10,100…)
loop @@lNextD ;Конец цикла
lodsb ;Дочитываем символ
cmp al,’-‘ ;Сравниваем его с ‘-‘
jne @@lSkipN ;Если нет =>lSkipN
neg bx ;Иначе bx=-bx
@@lSkipN:
mov ax,bx ;ax=bx=числу
clc ;Сбрасываем флаг переноса (нет ошибки)
jmp @@lExit ;Выходим
@@lExitE:
stc ;Устанавливаем флаг переноса(ошибка)
@@lExit:
pop bx ;Восстанавливаем из стека bx
pop cx ;Восстанавливаем из стека cx
pop dx ;Восстанавливаем из стека dx
pop si ;Восстанавливаем из стека si
ret ;Выходим из процедуры
doStr2Byte endp ;Конец описания процедуры
;—————————————————
; doFillBuf — Заполняет буфер заданным значением
;—————————————————
doFillBuf proc near ;Начало описания процедуры
push es ;Сохраняем es в стеке
push di ;Сохраняем di в стеке
push cx ;Сохраняем сx в стеке
push bx ;Сохраняем bx в стеке
mov bx,ds ;bx = ds
mov es,bx ;es = bx = ds
mov di,si ;di = si
cld ;Сбрасываем флаг направления (вперёд)
rep stosb ;Пишем сод. ax, cx раз в строку es:di
pop bx ;Восстанавливаем из стека bx
pop cx ;Восстанавливаем из стека cx
pop di ;Восстанавливаем из стека di
pop es ;Восстанавливаем из стека es
ret ;Выходим из процедуры
doFillBuf endp ;Конец описания процедуры
code ends ;Конец сегмента кода
end start ;Конец программы
cseg segment assume cs:cseg,ds:cseg,es:cseg,ss:cseg org 100h start: mov di,offset array;адрес массива mov cx,l_arr ;число элементов массива dec cx ;число сравнений на 1 меньше push cx ;сохраним его mov bx,[di] ;примем за минимум 1 элемент mov ax,bx ;и за максимум тоже add di,2 ;di -> 2 элемент push di chkmin: cmp [di],bx ;след. элемент меньше минимального ? jge nomin ;нет, проверяем дальше mov bx,[di] ;да, поместим его в bx nomin: add di,2 ;di -> след. элемент loop chkmin ;повторить cx раз pop di ;di -> 2 элемент pop cx ;восстановим счетчик chkmax: cmp [di],ax ;след. элемент больше максимального ? jle nomax ;нет, проверяем дальше mov ax,[di] ;да, отправим его в ax nomax: add di,2 ;di -> след. элемент loop chkmax ;повторить cx раз ret array dw 2456,321,-12,876,55,14,8,625,-324,156 l_arr=($-array)/2 cseg ends end start