尝试将数组加倍以增加数组以添加更多元素。 没有编译或运行时错误,但它不会让你在 5 之后输入更多元素 我不确定数组大小是否根本没有加倍或者发生了什么,因为你可以插入 5 个数字然后输入将去完成并打印统计数据。每次用户填充数组时,我都需要它使数组加倍,直到他们按下(ctrl d),然后它才会输出统计信息。
%define ARRAY_SIZE 5
%define ELEMENT_SIZE 4
%define EOF -1
segment .data
inputPrompt: db "Enter int value (ctrl-d to stop): ",0
intFormat: db "%d",0
output: db "Array[%d] = %d",10,0
dbout: db 10, 10,"[%d]",10,10,0 ; This is just for debugging output
newline: db 10,0 ; For whenever we need a newline
numElements: db "Number of elements: %d",10,0
outputSum: db "sum of elements: %d",10,0
minValue: db "Min value: %d",10,0
maxValue: db "Max value: %d",10,0
segment .bss
arrayPtr: resq 1 ; pointer to our array
intInput: resd 1
segment .text
global asm_main
extern printf, scanf, calloc, realloc
asm_main:
enter 0,0
;; Get memory for our array
;; Give calloc() number of element and element size
;; and calloc returns a pointer to zerioized memory
mov rdi, ARRAY_SIZE
mov rsi, ELEMENT_SIZE
call calloc
mov [arrayPtr], rax
mov rdi, [arrayPtr] ; Will use RDI and stosd to write the array
mov rcx, ARRAY_SIZE
mov r15, 0 ; R15 counts how many elements in our array
cld
inputLoop:
push rcx ; Save RCX and RDI across printf/scanf calls
push rdi
mov rdi, inputPrompt
call printf
mov rdi, intFormat
mov rsi, intInput
call scanf
cmp eax, EOF ; Did scanf() return -1 (didn't read anything?)
je inputDone
; check if the array is full, if so, double its size
cmp r15, ARRAY_SIZE
jl inputNotFull
; double the array size and copy the elements to the new array
mov rsi, [arrayPtr]
mov rdi, ARRAY_SIZE*2*ELEMENT_SIZE
call realloc
mov [arrayPtr], rax
mov rcx, [ARRAY_SIZE]
rep movsd
mov eax, ARRAY_SIZE
imul eax, 2
mov [ARRAY_SIZE], eax
; continue with the input
inputNotFull:
inc r15 ; O/w count another element & store it
xor rax, rax ; Clear out RAX for stosd to write array to mem
mov eax, [intInput]
pop rdi ; Restore RDI for stosd
stosd
pop rcx ; Restore RCS for loop instruction
dec rcx
jnz inputLoop
inputDone: ; Let's get ready to print
mov rdi, newline
call printf
mov rsi, [arrayPtr] ; Will use RSI and lodsd to read the array
mov rcx, r15 ; Store actual array size to RCX
mov rbx, 0
cld
printLoop:
xor rax, rax
xor rdx, rdx
lodsd
push rcx ; Save RCX and RSI across printf call
push rsi
mov rdi, output
mov rsi, rbx
movsx rdx, eax
call printf
inc rbx
pop rsi ; Restore RCX and RSI
pop rcx
loop printLoop
je printStats
printStats:
mov rdi, newline
call printf
mov rdi, numElements
mov rsi, r15
call printf
mov rax, 0 ; Initialize the sum to zero
mov rsi, [arrayPtr] ; Get the address of the array
mov rcx, r15 ; Store actual array size to RCX
cld
xor rdx, rdx ; Clear out RDX for the first add instruction
mov rax, 0 ; Initialize the sum to zero
mov rsi, [arrayPtr] ; Get the address of the array
mov rcx, r15 ; Store actual array size to RCX
cld
sumLoop:
lodsd ; Load the next element of the array into EAX
add rax, r8 ; Add the current sum to EAX
mov r8, rax ; Store the updated sum in R8
loop sumLoop
mov rdi, outputSum
mov rsi, r8
call printf
; Find the minimum value in the array
mov rax, [arrayPtr] ; Load the base address of the array into RAX
mov ebx, [rax] ; Load the first element of the array into EBX
mov rcx, r15 ; Loop counter will be the number of elements
dec rcx ; Decrement RCX since we've already loaded the first element
mov rsi, [rax] ; Initialize RSI to the first element
loopStart:
add rax, ELEMENT_SIZE ; Move the pointer to the next element
cmp [rax], ebx ; Compare the value at the current pointer to the minimum value
jge loopEnd ; If the value is greater than or equal to the minimum, skip to the end of the loop
mov ebx, [rax] ; Otherwise, update the minimum value
mov rsi, rax ; and store the address of the minimum value in RSI
loopEnd:
loop loopStart ; Repeat for the remaining elements of the array
mov rdi, minValue
mov rsi, rbx
call printf
; Find the maximum value in the array
mov rax, [arrayPtr] ; Load the base address of the array into RAX
mov ebx, [rax] ; Load the first element of the array into EBX
mov rcx, r15 ; Loop counter will be the number of elements
dec rcx ; Decrement RCX since we've already loaded the first element
mov rsi, [rax] ; Initialize RSI to the first element
loopStartd:
add rax, ELEMENT_SIZE ; Move the pointer to the next element
cmp [rax], ebx ; Compare the value at the current pointer to the maximum value
jle loopEndd ; If the value is less than or equal to the maximum, skip to the end of the loop
mov ebx, [rax] ; O/w, update the maximum value to the current value
mov rsi, rax ; Store the address of the current maximum value
loopEndd:
loop loopStartd
mov rdi, maxValue
mov rsi, rbx
call printf
mov rax, 0
leave
ret
我尝试增加 rcx,因为这决定了它是否会跳回 inputLoop:以获得更多输入,但随后会出现分段错误。
5
后不让你输入更多元素
这仅仅是因为 inputLoop 被告知进行 5 次迭代,之后它在 inputDone 中失败。
本质上,你需要的是一个无条件跳回到 inputLoop 顶部的 endless loop。当然,在 scanf 返回 EOF 时,总是会有已经可用的提前退出。
我试图增加 rcx ...但是它给出了一个分段错误。
上述问题实际上是一件幸事,因为正如您所报告的那样,增加迭代次数会触发“分段错误”。这是因为在调用 realloc 时没有遵循规则。地址进入 RDI,新的总大小进入 RSI;你把它弄反了!此外,如果 realloc 必须在物理上重新定位分配(大多数情况下不需要),那么它会将内容一起移动。你不需要从头做起,当然也不需要使用错误的寄存器。
我建立这个前提是数组中元素数量的动态适应应该遵循序列 5 -> 10 -> 20 -> 40 ...并且除非绝对必要,否则不执行任何更改(例如,在数组大小仍为 5 时接收到第 6 个输入,或者在数组大小仍为 10 时接收到第 11 个输入,依此类推):
mov rdi, ARRAY_SIZE
mov rsi, ELEMENT_SIZE
call calloc ; -> RAX
mov [arrayPtr], rax
add rax, ARRAY_SIZE * ELEMENT_SIZE
mov [arrayEnd], rax
...
mov rdi, [arrayPtr]
inputLoop:
push rdi ; (1)
mov rdi, inputPrompt
call printf
mov rdi, intFormat
mov rsi, intInput
call scanf
pop rdi ; (1)
cmp eax, EOF ; Did scanf() return -1?
je inputDone
cmp rdi, [arrayEnd]
jb inputNotFull
mov rdi, [arrayPtr]
mov rsi, [arrayEnd]
sub rsi, rdi
shl rsi, 1 ; Double current size
push rsi ; (2)
call realloc ; -> RAX
pop rsi ; (2)
mov [arrayPtr], rax
add rax, rsi
mov [arrayEnd], rax
shr rsi, 1
sub rax, rsi
mov rdi, rax ; Continue at midpoint
inputNotFull:
mov eax, [intInput]
stosd
jmp inputLoop
inputDone:
请注意,我引入了一个新变量 arrayEnd,它包含一个指向数组后面的指针,类似于 arrayPtr 包含一个指向数组开头的指针。
提示:你不应该检查 calloc 和 realloc 是否成功返回(检查 RAX)吗?