Выделения из исходной строки подстроки символов - 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
Объяснение кода листинга программы
- Код начинает выполняться с команды push edi, которая отправляет в стек текущее значение регистра edi.
- Следующая команда movzx ecx, byte ptr [edi] загружает в регистр ecx значение байта, на который указывает смещение от регистра edi.
- Команда lea esi, 1[edi] загружает в регистр esi значение, на которое указывает смещение от регистра edi плюс единица.
- Команда cld устанавливает флаг направления (DF) в 0, что означает, что при выполнении операций чтения и записи происходит копирование слева направо.
- Далее выполняется команда rep movsb, которая повторяет следующие действия до тех пор, пока флаг CF не станет равным 1: загрузка байта из памяти с помощью movzx ecx, byte ptr [edi] и копирование этого байта в буфер с помощью movsb.
- Команда mov al, cl копирует значение регистра cl в регистр al.
- Команда stosb копирует значение регистра al из регистра cl в память с помощью оператора [esi], где ESI указывает на текущий адрес в буфере.
- В конце выполнения кода выполняется команда pop edi, которая освобождает значение регистра edi из стека.
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д