我写的程序旨在从文本文件中获取一个表。该表格式如下:表格为NxN,第一行是数字N.表格的每一行都包含在自己的行中。因此,该文件有N + 1行。
程序应该在表格中读取,沿着对角线抓取数字,从左上角到右下角,然后将它们加在一起,将结果输出到屏幕。
目前,我正在开发一个程序,该程序将保存数字行的缓冲区以及用户希望检索的数字作为输入。目的是在eax中返回它。但是,似乎此过程目前会导致段错误。我查看了我的代码,这似乎对我有意义。下面是一个示例表文件和我的源代码。
hw6_1.dat
5
2 45 16 22 4
17 21 67 29 65
45 67 97 35 87
68 34 90 72 7
77 15 105 3 66
hw6_1.asm
; this program demonstrates how to open files for reading
; It reads a text file line by line and displays it on the screen
extern fopen
extern fgets
extern fclose
extern printf
extern exit
global main
segment .data
readmode: db "r",0
filename: db "hw6_1.dat",0 ; filename to open
error1: db "Cannot open file",10,0
format_1: db "%d",10,0
format_2: db "%s",10,0
segment .bss
buflen: equ 256 ; buffer length
buffer: resd buflen ; input buffer
tempBuff: resd buflen
segment .text
main:
pusha
; OPENING FILE FOR READING
push readmode ; 1- push pointer to openmode
push filename ; 2- push pointer to filename
call fopen ; fopen retuns a filehandle in eax
add esp, 8 ; or 0 if it cannot open the file
cmp eax, 0
jnz .L1
push error1 ; report an error and exit
call printf
add esp, 4
jmp .L4
; READING FROM FILE
.L1:
mov ebx, eax ; save filepointer of opened file in ebx
; Get first line and pass to ecx
push ebx
push buflen
push buffer
call fgets
add esp, 12
cmp eax, 0
je .L3
;convert string -> numeric
push buffer
call parseInt
mov ecx, eax
.L2:
push ecx
push ebx ; 1- push filehandle for fgets
push dword buflen ; 2- push max number of read chars
push buffer ; 3- push pointer to text buffer
call fgets ; get a line of text
add esp, 12 ; clean up the stack
cmp eax, 0 ; eax=0 in case of error or EOF
je .L3
push buffer ; output the read string
call printf
add esp, 4
push dword 2
push buffer
call grabNum ;Get the 3rd number in the current line. Space delimited.
;do somehing with the number. For now, lets just output to screen.
push eax
push format_1
call printf
add esp, 8
pop ecx
dec ecx
cmp ecx, 0
jg .L2
;CLOSING FILE
.L3:
push ebx ; push filehandle
call fclose ; close file
add esp, 4 ; clean up stack
.L4:
popa
call exit
parseInt:
push ebp
mov ebp, esp
push ebx
push esi
mov esi, [ebp+8] ; esi points to the string
xor eax, eax ; clear the accumulator
.I1:
cmp byte [esi], 48 ; end of string?
jl .I2
mov ebx, 10
mul ebx ; eax *= 10
xor ebx, ebx
mov bl, [esi] ; bl = character
sub bl, 48 ; ASCII conversion
add eax, ebx
inc esi
jmp .I1
.I2:
pop esi
pop ebx
pop ebp
ret 4
grabNum:
;This method will grab a specified number in a sequence.
;Ex: passed in is buffer and the number 4. The 4th number will be
;returned. It is assumed to be a space delimited buffer.
mov esi, [esp + 4]
mov ecx, [esp + 8]
dec ecx
.skipNum:
;for each number in ecx, advance past a number in esi.
;this is done by decrementing ecx each time a "non-digit" is detected.
;Since the buffer is known to be space delimted, this is a valid strategy.
cmp ecx, 0
je .doneSkipping
cmp byte [esi], 48
jl .numSkipped
cmp byte [esi], 57
jg .numSkipped
inc esi
jmp .skipNum
.numSkipped:
inc esi
dec ecx
jmp .skipNum
.doneSkipping:
;now we grab the number from buffer in its ASCII form. We place it in tempBuff,
;and call parseInt. This should leave the number in integer form waiting in eax
;after the end of the grabNum call.
cmp byte [esi + 1 * ecx], 48
jl .retGrab
cmp byte [esi + 1 * ecx], 57
jg .retGrab
mov ebx, [esi + 1 * ecx]
mov [tempBuff + 1 * ecx], ebx
inc ecx
jmp .doneSkipping
.retGrab:
mov [tempBuff + 1 * ecx], byte 0
push tempBuff
call parseInt
ret 8
准确地说,程序打印出“45”,第一行中的第二个数字,正如我此刻想要的那样,但似乎在第二行输出到屏幕之前抛出了段错误。
答案 0 :(得分:0)
无意中使用EBX寄存器来保存一些临时数据。这会破坏文件句柄并导致段错误。 EAX用于保存此数据,这解决了问题!
为了解决这个问题,我修改了这两行:
mov ebx, [esi + 1 * ecx]
mov [tempBuff + 1 * ecx], ebx
是:
mov eax, [esi + 1 * ecx]
mov [tempBuff + 1 * ecx], eax