Page 1 of 1

MASM - Reverse a string

#1 GunnerInc  Icon User is offline

  • "Hurry up and wait"
  • member icon




Reputation: 858
  • View blog
  • Posts: 2,282
  • Joined: 28-March 11

Posted 07 November 2011 - 06:36 PM

I see this question asked many times - "How do I reverse a string?", well there are many ways to do it. It is a fairly simple operation even at this low end. There are many ways to do it, this is only one way. Don't expect it to be super fast (it is fine for most situations) and is probably the simplest. The following code will use 2 buffers 1 for the original string and the second for the reversed string, 2 edit controls - 1 for original text and second for reversed string.
Attached Image
@@:
    mov		al, byte ptr [esi + ebx] 
    mov  	byte ptr[edi], al 
    inc		edi 
    dec		ebx
    js		Done 
    jmp		@B 
Look at that, simple right?
Let's do something worthwhile with it and explain a bit. As usual, sample app and source is attached.

The full procedure I put it in:
ReverseText proc uses esi edi ebx
LOCAL	hRev:DWORD

    invoke	SendMessage, hOriginal, WM_GETTEXTLENGTH, 0, 0
    test	eax, eax
    jz		NoText
    
    inc		eax
    mov		ebx, eax	
    
    invoke	HeapAlloc, hHeap, HEAP_ZERO_MEMORY, eax
    mov		esi, eax
    
    invoke	SendMessage, hOriginal, WM_GETTEXT, ebx, esi
    
    invoke	HeapAlloc, hHeap, HEAP_ZERO_MEMORY, ebx
    mov		edi, eax
    
    dec		ebx
    dec 	ebx
    
@@:
    mov		al, byte ptr [esi + ebx] 
    mov  	byte ptr[edi], al 
    inc		edi 
    dec		ebx
    js		NoMore 
    jmp		@B 

NoText:
    invoke	MessageBox, hMain, offset szNoText, NULL, MB_IConstop
    ret
    
NoMore:
    invoke	SendMessage, hReverse, WM_SETTEXT, 0,  hRev	
    invoke	HeapFree, hHeap, 0, esi	
    invoke	HeapFree, hHeap, 0, hRev
    
    ret
ReverseText endp


    invoke	SendMessage, hOriginal, WM_GETTEXTLENGTH, 0, 0
    test	eax, eax
    jz		NoText

We check to see if we have text to reverse, if not then we notify and leave.

    inc		eax
    mov		ebx, eax

WM_GETTEXTLENGTH returns the count of characters in the edit control not including the NULL terminator. Since the value is returned in eax, we increase the count in eax by 1. Then we save the count to ebx since that register is preserved across calls.

    invoke	HeapAlloc, hHeap, HEAP_ZERO_MEMORY, eax
    mov		esi, eax

Here we create a buffer for the original text plus a NULL and save the returned pointer in esi

    invoke	SendMessage, hOriginal, WM_GETTEXT, ebx, esi

We tell the edit control to put its text into the buffer pointed to by esi and the count is in ebx

    invoke	HeapAlloc, hHeap, HEAP_ZERO_MEMORY, ebx
    mov		hRev, eax
    mov		edi, eax

Now we create another buffer for the reversed string, we save the pointer to hRev so we can free it later and then move the pointer into edi.

    dec		ebx
    dec 	ebx

Now we decrease our counter by 2. Yes 2, why you say? Let's say you entered "abcd"
WM_GETTEXTLENGTH would return 4 then we added 1 to that count, so ebx == 5. So we decrease our count by 1 to skip the NULL, then since we want to start from the last character we decrease ebx by 1 more. BUT WAIT!!!! The letter "d" is at the 4 position in the string!!! So you say... Well, yes it is, but arrays are zero based - they start at 0. That trips up a lot of newcomers because they are used to arrays starting at 1.
a b c d 
0 1 2 3


@@: is called an anonymous label. They come in handy when you don't want to think of a name for the label :) jmp @B jumps to the previous @@ label.
@@:
    mov		al, byte ptr [esi + ebx] 
    mov  	byte ptr[edi], al 
    inc		edi 
    dec		ebx
    js		NoMore 
    jmp		@B

So, taking our example of "abcd" and ebx == 3 when we first enter the loop, we are telling the CPU to move the byte at position 3 (in the buffer pointed to by esi which is "d") into the byte register al, then we take that byte in al and move it into the 0 slot of our "reverse" buffer pointed to by edi.
Then we increase the pointer in edi by 1, and decrease our counter by 1. We check to see if the sign flag is set (we are below 0 if it is) if it is set, we are done else jump to the beginning of the loop.
Now ebx == 2 and the character we grab will be "c" and add that to the 1st position in the buffer pointed to by edi.

NoMore:
    invoke	SendMessage, hReverse, WM_SETTEXT, 0,  hRev	
    invoke	HeapFree, hHeap, 0, esi	
    invoke	HeapFree, hHeap, 0, edi

Here we display the "reversed" string in the other edit control - line 2
Free the "original" buffer - line 3
Then we free our "reversed" buffer.

Any questions?

Attached File(s)



Is This A Good Question/Topic? 2
  • +

Page 1 of 1