Marco Marco - 2 months ago 18
C Question

How can I traverse a string character by character

I have a C program that receive a string from the standard input and pass it to an function written in 32bit Assembly which which has to do following things:


  • check if the string is made only of alphanumeric character.

  • if the answer to the previous test is yes, then return the string as it is

  • if there are some non alphanumeric characters the function has to delete them.

  • once every character in the string has been checked the function has to return a the string without non alphanumeric characters.



Here an example of what that routine has to do:

INPUT: "only 4lph4numeric chars" ----> OUTPUT: "only 4lph4numeric chars"

INPUT: "heresomefor$bidden_chars#" ----> OUTPUT: "here some for bidden chars"

I'm new to assembly but I know how to compare character, I think that to remove one of them is enough to substitute it with a blank space.
The real problem is that I don't know how to traverse the string character by character, I've read something about
lods
but I've not understood how to use it.

Someone can help me?

Answer

This is how you do it. Next code was made with Visual Studio 2010 C++ console project. First, the assembly part, pay attention to the comments, how to get the string's address from stack, how the characters are visited, and the most important part, how the undesired chars are deleted:

.386
.model flat, C
.code
;-------------------------------------------------------
check_alphanum proc

;PRESERVE EBP, ESI.
  push ebp
  push esi

  mov  ebp, esp
  add  ebp, 12          ;GET PARAMETER'S ADDRESS.
  mov  esi, [ ebp ]     ;ESI POINTS TO ARRAY.
whil:
  mov  al, [ esi ]      ;GET CURRENT CHAR.
  cmp  al, 0            ;CHECK END OF ARRAY.
  je   finale           ;IF ( AL == 0 ) END OF STRING.

;CHECK IF CURRENT CHAR IS 0..9-A..Z-a..z.
  cmp  al, '0'
  jb   its_invalid      ;IF ( AL <  '0' ) INVALID.
  cmp  al, '9'
  jbe  its_valid        ;IF ( AL <= '9' ) VALID.
  cmp  al, 'A'
  jb   its_invalid      ;IF ( AL <  'A' ) INVALID.
  cmp  al, 'Z'
  jbe  its_valid        ;IF ( AL <= 'Z' ) VALID.
  cmp  al, 'a'
  jb   its_invalid      ;IF ( AL <  'a' ) INVALID.
  cmp  al, 'z'
  jbe  its_valid        ;IF ( AL <= 'z' ) VALID.
  jmp  its_invalid      ;INVALID BECAUSE AL > 'z'.

its_valid:
;NEXT CHAR TO PROCESS.
  inc  esi
  jmp  whil

its_invalid:
;DELETE CURRENT CHAR PUSHING ALL CHARS ONE PLACE TO THE LEFT.
  mov  edi, esi         ;EDI POINTS TO CURRENT CHAR TO DELETE.
  mov  ebx, esi         ;EBX ALSO POINTS TO CURRENT CHAR.
  inc  ebx              ;NOW EBX POINTS TO NEXT CHAR.
shifting_left:
  mov  al, [ ebx ]      ;AL = NEXT CHAR.
  mov  [ edi ], al      ;CURRENT CHAR REPLACED BY NEXT.
  cmp  al, 0
  je   end_shifting
  inc  edi
  inc  ebx
  jmp  shifting_left
end_shifting:

  jmp  whil             ;REPEAT PROCESS FOR NEXT CHAR.

finale:

;RESTORE EBP, ESI.
  pop  esi
  pop  ebp

  ret
check_alphanum endp
;-------------------------------------------------------
end

Now the C++ part. Previous procedure can be called like this, for example, from the "main" method:

extern "C" void check_alphanum ( char * arr );
...
char arr[] = "A213457B-3746DFA3-578EC20E-4567DFF2-08A1B3AC-7B125F3A";
check_alphanum( arr );

The resulting string is:

"A213457B3746DFA3578EC20E4567DFF208A1B3AC7B125F3A"

Next image shows where is the external assembly file in the project tree:

enter image description here

All you have to do is add a new file to your project, name it as you want but use the ".asm" extension, copy-paste my code in it, and that's it, ready to use (or ready to call).