Sure you can use edx. You just can't expect it to survive a call to a C function! If you would like edx preserved across the call(s) to "read", that can easily be arranged:
read:
push edx
push elemento1
push Fscanf
call scanf
add esp, 8
mov ebx, dword[elemento1]
pop edx
mov [matrixA+edx], ebx
ret
Normally, we'd leave the "pop edx" for last, right before the "ret", but since we need the original value, we do it "early". Since we don't alter it afterwards, edx retains its value after "read" returns. You do "mov edx, 0"..."mov edx, 4", but now that edx is "preserved" you could do "add edx, 4" and loop around filling more array elements until some "max" is reached (don't overflow the buffer!). I assume that's what you're working towards.
This is part of what I call the "C calling convention" - more correctly known as the "Intel ABI" (Application Binary Interface). I consider that name somewhat misleading, since the hardware doesn't care. It's just a "convention"... but we have to follow it if we expect to interface with C, and we "might as well" follow it in our own code for a consistant interface. With minor variations, this applies to other languages besides C, but we're interested in C right now... (also known as "cdecl", but I don't know how to pronounce that, so I just call it "the C calling convention")
Parameters are passed on the stack, pushed right to left (except the "Pascal" varient, which pushes 'em left to right). That is, the "last" parameter, as read in the C source, is pushed first. I prefer to think of it as the "closest" parameter to the name of the function is the "closest", up the stack, from the code to that function.
It is the responsibility of the calling code to "remove" these parameters ("clean up the stack") after the function returns. That's the "add esp, 4", etc. - it can be done by popping a "dummy" register, too, or with "lea"(!)... The "stdcall" (and "Pascal") varient expects the called function to "clean up the stack" - Windows APIs use this! - the called functions end in "ret 4","ret 8", etc. instead of a plain "ret". This isn't suitable for functions that can take a variable number of parameters - like "scanf" and "printf"... but we're interfacing with C anyway...
Certain registers are guaranteed to retain their value across a call, and are expected to retain their value across a callback function ("main" is a callback function!). ebx, esi, edi, and ebp need to be preserved - if we alter 'em, we need to restore their value - if we don't use 'em, we don't need to do anything, but it won't hurt to push/pop 'em "to be ready" in case we decide to use them.
main:
push epb
mov ebp, esp
; sub esp, ??? ; make space for "local" variables - we have none
push ebx
push esi
push edi
; our code
xor eax, eax ; claim "no error"
pop edi
pop esi
pop ebx
mov esp, ebp
pop ebp
ret
The "result" is returned in eax, or in the case of a 64-bit return value in edx:eax (rare, in my experience). There's no guarantee that a particular implementation of a C function *will* trash ecx... and edx... but it's "allowed", so we can't count on them surviving a call. The "return value" from printf and scanf (in eax) are "number of items" printed/read. It may be worth checking the return value from scanf to make sure the pesky user hasn't entered garbage (and clean up the mess if they have). The return value from printf probably isn't interesting, but it's in eax...
I think I'll leave "lea" for another post. I think I need a nap.
Later,
Frank