Выделения из исходной строки подстроки символов - Assembler

Узнай цену своей работы

Формулировка задачи:

Написать программу выделения из исходной строки подстроки символов заданной длины с указанного номера позиции, Pascal-string. Как переделать из Pascal-string в Z-string?
;Часть строки, следующую за первым вхождением заданного символа переписать
;в обратном порядке заданное число раз;(использовать процедуры)
.686
.model flat,stdcall
option casemap:none
 
mem_alloc proto :dword,:dword,:dword ; прототипы функций, используемых в программе
reverce proto :dword,:dword,:dword,:dword,:dword
 
include \masm32\include\msvcrt.inc
include \masm32\include\windows.inc
include \masm32\include\user32.inc
 
includelib \masm32\lib\msvcrt.lib
includelib \masm32\lib\user32.lib
 
.data
msg db 'Введите строку',0dh,0ah,1 ; единицы в конце строк нужны для того, чтобы функция CharToOem могла перекодировать весь текст за один раз
msg1 db 'Введите позицию символа начала подстроки ',0dh,0ah,1 ; до символа нуля
msg2 db 'Введите количество повторов подстроки',0dh,0ah,1
msg_exit db 0ah,'Для выхода нажмите клавишу ESC, для повторного ввода нажмите любую другую клавишу',0dh,0ah,1
msg_no db 0ah,'Позиция символа введена неверно',0dh,0ah,0
crlf db 0dh,0ah,0 ; знаки первода строки и каретки, будут использованы после ввода символа для 
; перевода курсора на новую строку
fmt db '%u',0
 
.code
 
start proc 
; локальные переменные
local string[MAX_PATH]:byte ; буффер для ввода строки, 260 байт
local position,str_len,crep:dword ; переменные для хранения начальной позиции подстроки, длины
; строки и количества повторений соответственно
 
invoke CharToOem,offset msg,offset msg ; функция перекодирует текст сообщений из кодировки CP1251 в CP866 для правильного отображения в консоли
mov msg+sizeof msg-1,0 ; заменим единицы в конце текстовых сообщений на нули
mov msg1+sizeof msg1-1,0
mov msg2+sizeof msg2-1,0
mov msg_exit+sizeof msg_exit-1,0
 
@gets:
 
invoke printf,offset msg ; выводим на экран приглашение к вводу строки
 
lea esi,string ; регистр esi указывает на начало буфера для ввода строки
invoke gets,esi ; функция ввода строки
 
invoke strlen,esi ; измерим длину введённой строки
mov str_len,eax ; и сохраним полученное значение в переменной и регистре
mov edi,eax
dec edi ; уменьшим на единицу полученное значение, так как нумерация символов в строке идёт с нуля
 
invoke printf,offset msg1 ; вывод на экран приглашения к вводу значения позиции начала подстроки
 
invoke scanf,offset fmt,addr position ; функция преобразует введённые цифры в число, в сответствии с указанным форматом ( в нашем случае
dec position ; - беззнаковое десятичное число)
cmp position,edi ; уменьшим введённое значение на 1 , сравним его с длиной строки
jb m1 ; если оно больше или равно длины строки
 
invoke printf,offset msg_no ; выведем сообщение об ошибочном вводе
jmp exit
 
m1:
invoke printf,offset msg2 ; иначе продолжаем выводом приглашения к вводу количества повторов подстроки
invoke scanf,offset fmt,addr crep 
 
dec crep ; полученное значение уменьшаем на единицу
 
mov ebx,str_len ; вычислим длину подстроки
sub ebx,position
cmp ebx,1
jnz m2
 
invoke printf,offset msg_no ; выведем сообщение об ошибочном вводе если длина подстроки равна единице
jmp exit
 
m2:
invoke mem_alloc,crep,ebx,str_len ; вызовем функцию выделения памяти под новую строку
; передав ей в качестве параметров кол-во повторов подстроки, её длину и длину исходной строки
 
mov ebx,eax ; и сохраним возращённый указатель на выделенный блок памяти в регистре ebx
 
invoke reverce,esi,ebx,position,str_len,crep
 
invoke printf,ebx ; выводим строку на экран
invoke free,ebx ; освобождаем память
exit:
invoke printf,offset msg_exit ; выводим сообщение о способе завершения программы
 
invoke _getch ; ожидание нажатия клавиши пользователем
cmp al,1bh
je @f
invoke getchar
jmp @gets
@@:
invoke _exit ; завершение программы
 
start endp
 
; —-----------------------------------------------------------------------
 
reverce proc uses ebx pstr:dword,pnewstr:dword,psubstr:dword,szstr:dword,crep
 
mov esi,pstr ;
переданный в процедура указатель на исходную строку
mov edi,pnewstr ; указатель на выделенный блок памяти
mov ecx,psubstr ; номер начального символа подстроки
rep movsb ; копируем исходную строку до начала подстроки в новую
 
mov ecx,szstr ; размер исходной строки
sub ecx,psubstr ; получаем размер подстроки
mov edx,ecx ; сохраняем в регистре edx для повторного использования
mov ebx,edi ; указатель на начало подстроки сохраняем в ebx
 
m1:
lodsb ; в цикле заносим в стек символы подстроки, подлежащие реверсированию
push ax
loop m1
 
mov ecx,edx ; восстанавливаем счётчик
m2:
pop ax ; перезаписывем в новую строку в обратном порядке ( последний символ строки будет лежать в стеке первым)
stosb
loop m2
 
mov esi,ebx ; устанавливаем указаетель на начало перевернутой подстроки
mov ecx,crep ; количество повторов подстроки
; регистр edi указывает на первый байт после последнего символа скопированной строки
m3:
push ecx ; сохранив счётчик в стеке
mov ecx,edx
rep movsb ; копируем подстроку 
pop ecx ; нужное число раз
loop m3
xor al,al ; в конец новой строки записываем символ нуля
stosb
 
ret ; возврат из процедуры
reverce endp
 
; —-----------------------------------------------------------------------
 
mem_alloc proc var1:dword,var2:dword,var3:dword
 
mov eax,var1 ; количество повторов умножаем на
mul var2 ; длину подстроки
add eax,var3 ; прибавляем к произведению длину строки
inc eax ; прибавляем единицу (для записи нулевого байта - признака конца новой строки)
 
invoke malloc,eax ; выделяем память под формируемую строку
 
ret
mem_alloc endp
end start

Решение задачи: «Выделения из исходной строки подстроки символов»

textual
Листинг программы
    push    edi
    movzx   ecx, byte ptr [edi]
    lea esi, 1[edi]
    cld
rep movsb
    mov al, cl
    stosb
    pop edi

Объяснение кода листинга программы

  1. Код начинает выполняться с команды push edi, которая отправляет в стек текущее значение регистра edi.
  2. Следующая команда movzx ecx, byte ptr [edi] загружает в регистр ecx значение байта, на который указывает смещение от регистра edi.
  3. Команда lea esi, 1[edi] загружает в регистр esi значение, на которое указывает смещение от регистра edi плюс единица.
  4. Команда cld устанавливает флаг направления (DF) в 0, что означает, что при выполнении операций чтения и записи происходит копирование слева направо.
  5. Далее выполняется команда rep movsb, которая повторяет следующие действия до тех пор, пока флаг CF не станет равным 1: загрузка байта из памяти с помощью movzx ecx, byte ptr [edi] и копирование этого байта в буфер с помощью movsb.
  6. Команда mov al, cl копирует значение регистра cl в регистр al.
  7. Команда stosb копирует значение регистра al из регистра cl в память с помощью оператора [esi], где ESI указывает на текущий адрес в буфере.
  8. В конце выполнения кода выполняется команда pop edi, которая освобождает значение регистра edi из стека.

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

13   голосов , оценка 4.154 из 5
Похожие ответы