News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

String Concatenation Help

Started by gothicmisery85, November 25, 2008, 04:53:40 AM

Previous topic - Next topic

gothicmisery85

I am writing a program that concatenates a source string onto a target string, and I can't figure out what I'm doing wrong. Any help would be appreciated. Here is what I have to do:

Write a procedure called St_concat that concatenates a source string to the end of a target string. Sufficient space must exist in the target string to accommodate the new characters. Pass pointers to the source and target strings. Here is a sample call:

.data
targetStr "ABCDE",10 DUP(0)
sourceStr "FGH",0
.code
INVOKE Str_concat, ADDR targetStr, ADDR sourceStr



Here is what I have so far:


TITLE String Concatenate                (StrConcat.asm)

; This program concatenates a source
; string to the end of a target string.


INCLUDE Irvine32.inc
INCLUDE Bsearch.inc

ARRAY_SIZE = 1

.data
array DWORD ARRAY_SIZE DUP(?)
targetStr BYTE "ABCDE",10 DUP(0)
sourceStr BYTE "FGH",0

LOWVAL = targetStr
HIGHVAL = sourceStr


.code
main PROC

; Fill an array with random signed integers
INVOKE FillArray, ADDR array, ARRAY_SIZE, LOWVAL, HIGHVAL

; Display the array
INVOKE PrintArray, ADDR array, ARRAY_SIZE
call WaitMsg

; Perform a bubble sort and redisplay the array
INVOKE BubbleSort, ADDR array, ARRAY_SIZE
INVOKE PrintArray, ADDR array, ARRAY_SIZE

call Str_concat

exit
main ENDP

;------------------------------------------------------------
BubbleSort PROC USES eax ecx esi,
pArray:PTR DWORD, ; pointer to array
Count:DWORD ; array size
;
; Sort an array of 32-bit signed integers in ascending
; order, using the bubble sort algorithm.
; Receives: pointer to array, array size
; Returns: nothing
;------------------------------------------------------------

mov ecx,Count
dec ecx ; decrement count by 1

L1: push ecx ; save outer loop count
mov esi,pArray ; point to first value

L2: mov eax,[esi] ; get array value
cmp [esi+4],eax ; compare a pair of values
jge L3 ; if [ESI] <= [EDI], no exchange
xchg eax,[esi+4] ; exchange the pair
mov [esi],eax


L3: add esi,4 ; move both pointers forward
loop L2 ; inner loop

pop ecx ; retrieve outer loop count
loop L1 ; else repeat outer loop

L4: ret

BubbleSort ENDP

;------------------------------------------------------------
FillArray PROC USES eax edi ecx edx,
pArray:PTR DWORD, ; pointer to array
Count:DWORD, ; number of elements
A:SDWORD,         ; ABCDE
B:SDWORD    ; FGH
;
; Fills an array with a random sequence of 32-bit signed
; integers between LowerRange and (UpperRange - 1).
; Returns: nothing
;------------------------------------------------------------
mov edi,pArray ; EDI points to the array
mov ecx,Count ; loop counter
mov edx,A
sub edx,B ; EDX = absolute range (0..n)

L1: mov eax,edx ; get absolute range
add eax,B ; bias the result
stosd ; store EAX into [edi]

mov edx,OFFSET targetStr
call WriteString

loop L1

ret

call Str_concat
FillArray ENDP

;------------------------------------------------------------
PrintArray PROC USES eax ecx edx esi,
pArray:PTR DWORD, ; pointer to array
Count:DWORD ; number of elements
;
; Writes an array of 32-bit signed decimal integers to
; standard output, separated by commas
; Receives: pointer to array, array size
; Returns: nothing
;------------------------------------------------------------
.data
comma BYTE ", ",0

.code
mov esi,pArray
mov ecx,Count
cld ; direction = forward

L1: lodsd ; load [ESI] into EAX

loop L1

call Crlf
ret
PrintArray ENDP

;------------------------------------------------------------
Str_concat PROC USES eax ecx esi,
pArray:PTR DWORD, ; pointer to array
Count:DWORD ; array size
;
; Sort an array of 32-bit signed integers in ascending
; order, using the bubble sort algorithm.
; Receives: pointer to array, array size
; Returns: nothing
;------------------------------------------------------------
.code
INVOKE Str_concat, ADDR targetStr, ADDR sourceStr

mov ecx,Count
dec ecx ; decrement count by 1

L1: push ecx ; save outer loop count
mov esi,pArray ; point to first value

L2: mov eax,[esi] ; get array value
cmp [esi+4],eax ; compare a pair of values
jge L3 ; if [ESI] <= [EDI], no exchange
xchg eax,[esi+4] ; exchange pair
mov [esi],eax

mov edx,OFFSET sourceStr
call WriteString


L3: add esi,4 ; move both pointers forward
loop L2 ; inner loop

pop ecx ; retrieve outer loop count
loop L1 ; else repeat outer loop

L4: ret

Str_concat ENDP

END main

donkey

Judging from your source code which appears to be little more than an inefficient bubble sort routine and some array stuff to build the example, it doesn't look like you even attempted to do your homework. As a matter of fact you just renamed the bubble sort routine Str_concat even though it has nothing to do with string concatenation, pretty lame attempt to look like you at least tried, I mean you could have at least changed the freaking comments. Anyway, if you're not interested in execution speed this will do quite well....

//You are using NULL terminated strings so scan the targetStr for NULL
mov edi, offset targetStr
mov al, NULL
repne scasb ; scan forward for null starting at the address in EDI
// EDI now points to one past the first NULL so subtract 1 from it and copy the second string to that location
dec edi
// copy a string of unknown length to the buffer, you can perform bounds checks here if you like...
mov esi, offset sourceStr
:
mov al,[esi]
mov [edi],al
inc esi
inc edi
test al,al
jnz <
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

MichaelW

Quotepretty lame attempt to look like you at least tried

And apparently a pretty low opinion of the level of understanding here :toothy
eschew obfuscation

Vortex

Hi gothicmisery85,

You can download the Masm32 package. To help you, it contains a lot of string functions to study.

drunk_sinsi


ARRAY_SIZE = 1

.data
array DWORD ARRAY_SIZE DUP(?)

So the array has...1 dword? Easy to bubble sort then. What does the array have to do with anything?



Str_concat PROC USES eax ecx esi,
pArray:PTR DWORD, ; pointer to array
Count:DWORD ; array size
;...comment
.code
INVOKE Str_concat, ADDR targetStr, ADDR sourceStr
;...code
Str_concat ENDP

???Proc definition of parameters is different to invoke parameters, and this will be a never-ending loop, until you run out of stack...

Must admit, it looks like a cut/paste...well, we always say "show us your code" for homework  :bdg

gothicmisery85

Well to be perfectly honest, I missed the day my teacher was lecturing, so therefore, I have to figure it all out by myself, and my book isn't so self-explanitory.

japheth

Quote from: donkey on November 25, 2008, 05:16:07 AM
//You are using NULL terminated strings so scan the targetStr for NULL
mov edi, offset targetStr
mov al, NULL
mov ecx,-1     ; line added
repne scasb ; scan forward for null starting at the address in EDI



Mirno

Normally I hate people like this, who expect us to do their homework for them because they were "ill", or "too busy working three jobs to pay their way through university/supporting their sick grand mother/buying booze", but this one is just so amazingly crass it's fantastic!

You've got to admit it's better than the normal "wah, wah, wah, send me teh codez, wah, wah, KTHXBAI" requests!

Mirno

Mark Jones

Quote from: gothicmisery85 on November 25, 2008, 11:46:30 AM
...therefore, I have to figure it all out by myself, and my book isn't so self-explanitory...

Fortunately for you, this is a great platform for learning. :bg

Some things, a book simply cannot teach. A book can spend 5 chapters introducing a topic, 2 chapters covering one instruction, and give a test, and still not "teach" much of anything. (No offense Kip, I'm sure your book is great, but everyone knows that learning is not something a BOOK does, it is what the student does.)

I suppose you have noticed GM85, the forum here can get a little bit heated when it comes to homework questions. Most people here will help you understand something as long as you a), show that you genuinely attempted a solution, and b), ask general questions.

For this assignment, consider the following procedure:

http://www.masm32.com/board/index.php?topic=5338.msg40012#msg40012

This is a fully-commented ASCII string concatination routine. Now it is probably a bit advanced at the moment, but if you look up what "repne scasb" and "movsd/w" do, it should make sense. (By the way, I would not suggest copying-and-pasting this into your homework... the instructor is going to know it is someone else's work -- same with any code here, this is a well-known public forum and many instructors frequent here.) :U

If you do not understand a concept, state what is not understood and we will help. When you do "get it" GM85, stick around and teach it to the next newcomer whom asks, so that they may also learn.
"To deny our impulses... foolish; to revel in them, chaos." MCJ 2003.08

gothicmisery85

Thanks for all the help.  :bg I appreciate it, but I got help from my teacher, and we came up with this solution.


TITLE String Concatenate                (StrConcat.asm)

; This program concatenates a source
; string to the end of a target string.


INCLUDE Irvine32.inc
INCLUDE Bsearch.inc

STRING_SIZE = 10


Str_concat PROTO,
source:PTR BYTE, ; source string
target:PTR BYTE ; target string


.data
targetStr BYTE "ABCDE",10 DUP(0)
sourceStr BYTE "FGH",0

.code
main PROC

; Display
mov edx,OFFSET targetStr
call WriteString

call Crlf

call WaitMsg

mov eax,LENGTHOF sourceStr

INVOKE Str_concat, ADDR sourceStr, ADDR targetStr

mov edx,OFFSET targetStr
call WriteString

call Crlf

exit
main ENDP

;------------------------------------------------------------
FillString PROC USES eax edi ecx edx,
pString:PTR DWORD, ; pointer to array
Count:DWORD, ; number of elements
string_1:SDWORD,         ; ABCDE
string_2:SDWORD    ; FGH
;
; Fills the string with "ABCDE", then concatenates, "FGH" onto it.
; Returns: nothing
;------------------------------------------------------------
mov edi,pString ; EDI points to the string
mov ecx,Count ; loop counter
mov edx,string_1
sub edx,string_2 ; EDX = absolute range (0..n)

L1: mov eax,edx ; get absolute range
add eax,string_2 ; bias the result
stosd ; store EAX into [edi]

loop L1

ret

FillString ENDP
;------------------------------------------------------------
Str_concat PROC USES eax ecx esi edi,
source:PTR BYTE, ; source string
target:PTR BYTE ; target string
;------------------------------------------------------------
mov ecx,eax ; EAX = length source

mov esi,source
mov edi,target
add edi,5
cld ; direction = forward
rep movsb ; copy the string

ret

Str_concat ENDP

END main

drunk_sinsi


mov ecx,eax  ; EAX = length source

If you're going to pass another parameter, it's best to add it to the PROC declaration e.g.

Str_concat PROC USES eax esi edi,
                source:PTR BYTE,
                target:PTR BYTE,
                sourcelength:DWORD

But since you're using asciiz (null-terminated) strings, the length isn't necessary.



add edi,5

This bit makes the procedure only good for target strings 5 bytes long.
Try something like this:

Str_concat PROC source:PTR BYTE,target:PTR BYTE

  cld
  mov ecx,source
  mov edx,target

;find the end of the target string
;this replaces the "add edi,5" line so it works with any size asciiz string.
find_end:
  mov al,[edx]
  inc edx
  test al,al
  jnz find_end
;EDX points to the byte after the target's end-of-string 00, so adjust it
  dec edx    ;now EDX points to the 00

;now copy the string from ECX to EDX. If the source is longer than the
; remainder of the target, bad things will probably happen (buffer overrun).
copy_it:
  mov al,[ecx]
  mov [edx],al
  inc ecx
  inc edx
  test al,al
  jnz copy_it
  ret
Str_concat ENDP


There are so many different ways of doing string concatenations - find one you can
follow and use it. This one and donkey's are easy to understand, but will run pretty slowly
when you start using long strings.

gothicmisery85

Yeah, I can see what you're saying about the bit making the procedure only good for target strings 5 bytes long.  :bg Thanks for the useful additional information, its good to know.  :bg

ecube

targetStr BYTE "ABCDE",10 DUP(0) is silly becaues dup(0) actually adds size to your final pe file(exe,dll,etc..) it's alot better to use a buffer and copy the original string over, then append the other string.


.586
.model flat, stdcall  ;32 bit memory model
option casemap :none  ;case sensitive

include \masm32\include\masm32rt.inc
.data
firststring byte 'ABCDE',0
secondstring byte 'FGH',0
.data?
mybuffer byte 100 dup(?)

.code
start:
invoke lstrcpy,addr mybuffer,addr firststring   
invoke lstrcat,addr mybuffer,addr secondstring
invoke ExitProcess,0
end start