Почему программа на языке ассемблера masm32 некорректно подсчитывает произведение элементов массива?

Как можно улучшить существующий код на ассемблере MASM, чтобы обойти двумерный массив и преобразовать элементы в строку для их последующего вывода?
  • 18 апреля 2024 г. 15:10
Ответы на вопрос 2
Проблема может быть связана с неправильным использованием указателей или неправильной обработкой элементов массива. Рекомендуется тщательно проверить работу с указателями, правильное обращение к элементам массива и правильные операции перемножения.

Для улучшения существующего кода и обхода двумерного массива в строку для последующего вывода можно воспользоваться следующим подходом:
1. Создать циклы для обхода строк и столбцов массива.
2. Преобразовать каждый элемент массива в строку, например, используя команды преобразования числа в строку (например, `itoa`).
3. Собрать все строки в одну строку для последующего вывода.

Пример кода на языке ассемблера MASM для преобразования двумерного массива в строку:

```assembly
.DATA
array DWORD 1, 2, 3, 4, 5, 6, 7, 8, 9
result DB 100 DUP(?)
buffer DB 10 DUP(?)

.CODE
main PROC
    mov esi, OFFSET array       ; Установка указателя на начало массива
    mov ecx, LENGTHOF array     ; Установка количества элементов массива

    mov edi, OFFSET result      ; Установка указателя на начало строки результата
    mov BYTE PTR [edi], 0       ; Обнуление строки результата

loop_start:
    mov eax, DWORD PTR [esi]    ; Загрузка значения элемента массива
    call ConvertToString        ; Вызов функции преобразования числа в строку
    add edi, eax                ; Добавление длины строки к указателю результата

    add esi, 4                  ; Переход к следующему элементу массива
    dec ecx                     

    jnz loop_start

    mov BYTE PTR [edi], 0       ; Добавление нуля в конец строки результата

    lea esi, result             ; Установка указателя на строку результата
    mov edx, LENGTHOF result    ; Установка длины строки
    mov eax, 4                  ; Вызов системного вызова для вывода строки
    int 0x80

    ret
main ENDP

ConvertToString PROC
    mov ebx, OFFSET buffer      ; Установка указателя на буфер для преобразования
    mov DWORD PTR [ebx], eax    ; Сохранение длины строки
    push ebx

    push eax
    lea eax, [ebx + 4]          ; Установка указателя на конец строки в буфере
    call itoa                   ; Преобразование числа в строку
    pop eax

    mov eax, DWORD PTR [ebx]    ; Загрузка длины строки
    inc eax                     ; Увеличение длины на 1 для нуль-терминатора
    pop ebx

    ret
ConvertToString ENDP

END main
```

Этот код обходит двумерный массив `array` и преобразует каждый элемент в строку, затем собирает все строки в одну строку `result` и выводит её на экран.
.686
.model flat, stdcall ; определяем модель памяти и
; модель вызова функций
option casemap:none ; отключаем регистрозависимость
; Библиотеки и подключаемые файлы проекта
;--------------------------------------------
include C:\masm32\include\windows.inc
include C:\masm32\include\user32.inc
include C:\masm32\include\kernel32.inc
include C:\masm32\include\masm32.inc
includelib C:\masm32\lib\user32.lib
includelib C:\masm32\lib\kernel32.lib
includelib C:\masm32\lib\masm32.lib
; Сегмент данных
;--------------------------------------------
.data
sConsTitle BYTE "Laba №4", 0
Arr DWORD 2, 2, 2, 3 ; двумерный массив 4x4
RowSize = ($ - Arr)
DWORD 2, 2, 2, 2
DWORD 1, 2, 2, 2
DWORD 2, 2, 2, 2
typeArr BYTE TYPE Arr ; размер элемента в байтах
row BYTE 4 ; число строк
col BYTE 4 ; число столбцов
i BYTE 0 ; индекс строки
j BYTE 0 ; индекс столбца
sum DWORD 0 ; переменная для хранения суммы
resultText BYTE "Answer: "
resultStr BYTE 20 DUP(?), 0
buffer BYTE 20 DUP(?), 0
tab BYTE ' ', 0
clrt BYTE 0Ah, 0Dh, 0
; Сегмент кода
;--------------------------------------------
.code
start:
; вывод заголовка консоли
invoke SetConsoleTitle, ADDR sConsTitle
; вывод массива
xor ecx, ecx ; ECX = 0
mov cl, row ; ECX = row - загружаем счётчик строк
mov esi, 0 ; ESI = 0 - указатель на нулевую строку
loop_row_1:
push ecx ; сохраняем счётчик внешнего цикла в стек
xor ecx, ecx ; ECX = 0
mov cl, col ; ECX = col - загружаем счётчик столбцов
mov ebx, 0 ; EBX = 0 - указатель на нулевой столбец
loop_col_1:
mov eax, Arr[esi][ebx] ; EAX <- Arr[i][j]
push ebx ; сохраняем регистры перед
; использованием ltoa и StdOut
push ecx
push esi
invoke ltoa, eax, ADDR buffer ; преобразование Arr[i][j] в строку
invoke StdOut, ADDR buffer ; вывод Arr[i][j]
invoke StdOut, ADDR tab ; вывод TAB
pop esi ; восстанавливаем регистры из стека
pop ecx
pop ebx
add ebx, TYPE Arr ; увеличиваем указатель столбцов на
; размер одного элемента
loop loop_col_1 ; проверяем окончание строки
invoke StdOut, ADDR clrt ; переходим на следующую строку
add esi, RowSize ; увеличиваем указатель строки на
; размер одной строки
pop ecx ; восстанавливаем счётчик внешнего цикла
loop loop_row_1 ; проверяем окончание массива
;--------------------------------------------
; вычисление произведения элементов, делящихся на 2
xor ecx, ecx ; ECX = 0
mov cl, row ; ECX = row - загружаем счётчик строк
mov esi, 0 ; ESI = 0 - указатель на нулевую строку
mov i, 0
mov sum, 1 ; начальное значение произведения
loop_row_2:
    push ecx ; сохраняем счётчик внешнего цикла в стек
    xor ecx, ecx ; ECX = 0
    mov cl, col ; ECX = col - загружаем счётчик столбцов
    mov ebx, 0 ; EBX = 0 - указатель на нулевой столбец
    mov j, 0
loop_col_2:
    mov eax, Arr[esi][ebx] ; EAX <- Arr[i][j]
    test eax, 1 ; проверяем делится ли текущий элемент на 2
    jnz not_divisible ; если не делится, переходим к следующему элементу

    ; умножаем текущий элемент на произведение
    imul sum, eax

not_divisible:
    inc j ; увеличиваем индекс столбца
    add ebx, TYPE Arr ; увеличиваем указатель столбцов на размер одного элемента
    loop loop_col_2 ; проверяем окончание строки

;--------------------------------------------
; вывод результата
invoke ltoa, sum, ADDR resultStr ; преобразование SUM в строку
invoke StdOut, ADDR resultText ; вывод результата
invoke Sleep, INFINITE
; завершение процессов Windows
invoke ExitProcess, NULL
; окончание сегмента start
end start

Есть ещё такой вариант, но он просто не ассемблируется
Похожие вопросы