2016-05-10 2 views
1

Для моего назначения я пытаюсь написать функцию Insert, такую ​​как вставка C++. Моя функция должна вставить одну строку в другую строку в определенном месте.Как вставить строку в другую строку в определенной позиции в Assembly?

Входы:

destination : Be my friend today 
source  : good 
position : 6 

Выходные:

Be my good friend today 

Как я должен сделать комнату в середине строки?

Это мой код до сих пор.

Insert PROC PROC uses edi esi ebx ecx, 
        destination:DWORD , 
        source:DWORD, 
        position:DWORD 

    mov esi,destination   ;add esi address of str 
    add esi,position 
    add esi,4      ;lenght of source 
    mov edi,destination   
    add edi,position 

    ;I don't know what should I do in here 

    ;How should I make room in the middle of destination ? 
    ;How should I insert at certain position + source length :-(
    ;Also, I shouldn't use loop and lea. 


    rep movsb 

    Insert ENDP 
+0

Попробуйте мой ответ и дайте мне знать! –

ответ

3

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

Я собираюсь предположить следующее:

1) destination имеет достаточно памяти в его адрес, чтобы держать заполненную строку без перезаписи каких-либо других переменных.

2) Вы на самом деле хотите вставить "good " (с завершающими пробелами), а не "good", так как если вы вставите "good" вы в конечном итоге с "Be my goodfriend today" (без пространства между добром и другом).

3) На самом деле вы намеревались указать позицию 5, а не позицию 6, поскольку C++ insert использует позиции с нулевой позицией (позиция 0 - это первый символ, позиция 1 - вторая и т. Д.).

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

destination : Be my frienfriend today 

Существует один улов, хотя здесь: вы должны скопировать назад с конца destination, чтобы избежать переписывания символов, которые еще не были скопированы, - если вы начинаете со смещения 6 и копируете это значение до смещения 11, вы должны перезаписать значение смещения 11, которое необходимо скопировать на смещение 16 во-первых, и вместо этого вы получите примерно следующее:

destination : Be my frienfrienfrienfri 

Копируя назад, вы избегаете этой проблемы. Простой условный переход с соответствующими операторами dec или sub будет работать нормально.

После помещения места для исходной строки, как указано выше, его простой вопрос по загрузке регистров должным образом и использование rep movsb для копирования источника в пункт назначения в указанной позиции, перезапись символов, которые вы уже скопировали.

И с этим destination будет содержать "Be my good friend today".

+0

Спасибо, это очень полезно @Matt Jordan – Jeff

0

Вы должны зарезервировать память для новой «строки» с длиной ога исходной строки + длиной строки для вставки. Затем скопируйте символы из исходной строки, до указанной позиции (используйте LODSB или LODSW в зависимости от ширины символа). point eds к новой выходной строке и точке edi в исходный массив. установите CX в значение в позиции. Это скопирует символы из источника в новую память назначения. Затем укажите edi на строку для вставки и установите cx в длину строки для вставки. Запустите LODSW снова и, наконец, наведите edi на позицию исходной строки и установите cx на длину исходной строки за вычетом позиции и запустите lodsw в последний раз.

+0

Вы должны зарезервировать память для новой «строки» с длиной og исходной строки + длиной строки для вставки. Как мне это сделать? Я не должен использовать LODSB и LODSB :-( – Jeff

+0

Вы имеете в виду 'movsb'?' Lodsb', просто загружает 'al', он не хранится. В любом случае использование' lodsb' или 'movsb' без префикса rep только хорошо для сохранения размера кода. @Keihan: просто напишите цикл, который копирует байты обычным способом. 'lodsb' - это просто' mov al, [esi] 'и' inc [esi] '. –

0

Для новой строки:

копирования символов из оригинала, а затем скопировать в новых персонажей, а затем скопировать хвост оригинала.


В месте:

копия хвост колонны, чтобы сделать пробел, чтобы сохранить новую строку. Это как memmove: поскольку источник и место назначения дублирования копии, вы должны начать с последнего символа, так что вы не переписываете символы, которые еще не скопированы. Это также то же самое, что и InsertionSort's copying to make room for a new element.


Возможно, вам захочется использовать два регистра для отслеживания положения источника и места назначения.

0

Ваша проблема может быть решена с помощью двух функций: первая функция сдвигает символы строки в одну позицию вправо, начиная с позиции SI, вторая функция вызывает первый CX раз. Эти функции необходимы, чтобы освободить место для вставки новой строки (я думаю, вы можете объединить их в одну функцию). После этого легко заменить строку назначения исходной строкой. Я выбрал "$", чтобы закончить строки, вы можете изменить его нулями или что-то другое:

shift_right_once

;--------------------------------------------------- 
;SHIFTS ONE POSITION TO THE RIGHT ALL THE CHARACTERS 
;OF A STRING STARTING AT POSITION POINTED BY "SI". 
;STRING MUST FINISH WITH "$". 
;EXAMPLE: SI = 6 
;  INPUT = 'Be my friend today$$$$$$$$$$$$$$$$' 
;  OUTPUT = 'Be my ffriend today$$$$$$$$$$$$$$$' 
;MODIFIED REGISTERS : AX, SI. 

shift_right_once proc 
    mov al, [ si ] ;FIRST CHAR TO START PROCESS. 
shifting: 
    cmp al, '$'  
    je end_shifting ;IF (END OF STRING) 
    inc si 
    mov ah, [ si ] 
    mov [ si ], al 
    xchg al, ah 
    jmp shifting 
end_shifting:  
    ret 
shift_right_once endp 

shift_right_cx

;--------------------------------------------------- 
;SHIFTS "CX" POSITIONS TO THE RIGHT ALL THE CHARACTERS 
;OF A STRING STARTING AT POSITION POINTED BY "SI". 
;STRING MUST FINISH WITH "$". 
;EXAMPLE: SI = 6 
;   CX = 3 
;  INPUT = 'Be my friend today$$$$$$$$$$$$$$$$' 
;  OUTPUT = 'Be my ffffriend today$$$$$$$$$$$$$' 
;MODIFIED REGISTERS : AX, CX. 

shift_right_cx proc 
    push si 
    call shift_right_once  ;CALL PREVIOUS FUNCTION. 
    pop si 
    loop shift_right_cx  
    ret 
shift_right_cx endp 

Следующая маленькая программа (сделанные с EMU8086) показывает, как их использовать:

.stack 100h 

.data 

destination db 'Be my friend today$$$$$$$$$$$$$$$$' 
source  db 'good $' 
length  dw 5    ;LENGTH OF "SOURCE". 
position dw 6    ;POSITION TO INSERT. 

.code 
    mov ax, @data 
    mov ds, ax  
    mov es, ax  

;SHIFT CHARS TO THE RIGHT TO MAKE ROOM FOR NEW STRING. 
    mov cx, length   ;HOW MANY CHARS TO PUSH. 
    mov si, offset destination 
    add si, position 
    call shift_right_cx 

;OVERWRITE OLD CHARS WITH THE NEW ONES. 
    mov cx, length   ;HOW MANY NEW CHARS. 
    mov di, si    ;DI = DESTINATION. 
    mov si, offset source ;SI = SOURCE. 
    rep movsb    ;DO { [DI]=[SI] } WHILE CX>0. 

;WAIT FOR A KEY. 
    mov ah, 0 
    int 16h   

;FINISH PROGRAM.  
    mov ax, 4c00h 
    int 21h   

;--------------------------------------------------- 
;SHIFTS "CX" POSITIONS TO THE RIGHT ALL THE CHARACTERS 
;OF A STRING STARTING AT POSITION POINTED BY "SI". 
;STRING MUST FINISH WITH "$". 
;EXAMPLE: SI = 6  | 
;   CX = 3 
;  INPUT = 'Be my friend today$$$$$$$$$$$$$$$$' 
;  OUTPUT = 'Be my ffffriend today$$$$$$$$$$$$$' 
;MODIFIED REGISTERS : AX, CX. 

shift_right_cx proc 
    push si 
    call shift_right_once ;SHIFT RIGHT CHARACTERS ONCE. 
    pop si 
    loop shift_right_cx  
    ret 
shift_right_cx endp 

;--------------------------------------------------- 
;SHIFTS ONE POSITION TO THE RIGHT ALL THE CHARACTERS 
;OF A STRING STARTING AT POSITION POINTED BY "SI". 
;STRING MUST FINISH WITH "$". 
;EXAMPLE: SI = 6  | 
;  INPUT = 'Be my friend today$$$$$$$$$$$$$$$$' 
;  OUTPUT = 'Be my ffriend today$$$$$$$$$$$$$$$' 
;MODIFIED REGISTERS : AX, SI. 

shift_right_once proc 
    mov al, [ si ] ;FIRST CHAR TO START PROCESS. 
shifting: 
    cmp al, '$'  
    je end_shifting ;IF (END OF STRING) 
    inc si 
    mov ah, [ si ] 
    mov [ si ], al 
    xchg al, ah 
    jmp shifting 
end_shifting:  
    ret 
shift_right_once endp 

Надеюсь, это вам поможет.

+0

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

+0

@PeterCordes, вот почему я предложил объединить их (третья строка первого абзаца). –

+1

А, я только снял это. –

Смежные вопросы