现在位置: 首页 > 汇编语言 > 正文

汇编语言 - 数组

数组是连续存放的同类型数据集合。在汇编中,数组就是内存中一段连续的空间,通过基址加偏移的方式来访问每个元素。


一维数组定义

实例

; 数组的定义方式

section .data
    ; 方式1:逐个列出元素
    arr1 dd 10, 20, 30, 40, 50  ; 5 个双字元素的数组

    ; 方式2:用 dup 初始化
    arr2 dd 10 dup(0)            ; 10 个双字,全为 0

    ; 方式3:字节数组
    bytes db 1, 2, 3, 4, 5, 6   ; 6 个字节

    ; 方式4:字符数组(字符串)
    chars db 'runoob', 0         ; 7 字节

    ; 数组长度计算(编译时)
    arr1_len equ ($ - arr1) / 4  ; 双字数组的元素个数
    arr2_len equ ($ - arr2) / 4
    bytes_len equ ($ - bytes)    ; 字节数组,不需除法

section .bss
    ; 未初始化的数组
    buffer resd 100              ; 预留 100 个双字的空间

数组元素访问

访问数组元素使用 基址 + 索引 × 元素大小 的寻址方式:

实例

; 文件路径:array_access.asm
; 数组元素的读取和写入

section .data
    nums dd 100, 200, 300, 400, 500   ; 5 个元素
    nums_len equ ($ - nums) / 4

section .text
    global _start

_start:
    ; 访问第 0 个元素(下标 0)
    mov eax, [nums]              ; eax = 100

    ; 访问第 2 个元素(下标 2)
    mov eax, [nums + 2 * 4]      ; eax = nums[2] = 300
    ; 2 * 4 = 8,从 nums 偏移 8 字节

    ; 使用寄存器作为下标
    mov esi, 3                   ; 下标 = 3
    mov eax, [nums + esi * 4]    ; eax = nums[3] = 400

    ; 修改数组元素
    mov dword [nums + 4], 250    ; nums[1] = 250
    ; 数组中现在:100, 250, 300, 400, 500

    ; 使用 EBX 作为基址寄存器
    mov ebx, nums                ; ebx = 数组基址
    mov eax, [ebx + 4 * 4]       ; eax = nums[4] = 500

    mov eax, 1
    mov ebx, 0
    int 0x80

注意:[nums + esi * 4] 中的乘以 4 是因为每个元素是 4 字节(双字)。如果是字节数组(db),直接写成 [arr + esi];字数组(dw),写成 [arr + esi * 2]


数组遍历

实例

; 文件路径:array_traverse.asm
; 遍历数组并计算总和

section .data
    numbers dd 5, 10, 15, 20, 25, 30, 35, 40, 45, 50
    count equ ($ - numbers) / 4   ; 元素个数

section .text
    global _start

_start:
    mov ecx, count                ; 循环次数
    mov esi, 0                    ; 下标(从 0 开始)
    mov eax, 0                    ; 累加和

sum_loop:
    add eax, [numbers + esi * 4]  ; 累加数组元素
    inc esi                       ; 下标 +1
    loop sum_loop
    ; eax = 5+10+15+...+50 = 275

    ; 另一种遍历方式:使用指针
    mov ecx, count
    mov ebx, numbers              ; ebx 指向数组起始
    mov eax, 0                    ; 累加和

sum_loop2:
    add eax, [ebx]                ; 累加当前元素
    add ebx, 4                    ; 指针移动到下一个元素
    loop sum_loop2
    ; eax = 275

    mov ebx, eax                  ; 退出码 = 累加和
    mov eax, 1
    int 0x80

数组查找

实例

; 文件路径:array_search.asm
; 在数组中查找指定值

section .data
    data dd 12, 45, 67, 23, 89, 34, 56, 78, 90, 11
    data_len equ ($ - data) / 4
    target dd 23                   ; 要查找的值
    found_msg db 'Found at index: ', 0
    found_len equ $ - found_msg
    notfound_msg db 'Not found (runoob)', 0xA
    notfound_len equ $ - notfound_msg
    newline db 0xA

section .text
    global _start

_start:
    mov ecx, data_len             ; 循环次数
    mov esi, 0                    ; 当前下标

search_loop:
    mov eax, [data + esi * 4]     ; 加载当前元素
    cmp eax, [target]             ; 是否等于目标值
    je  found                     ; 找到了

    inc esi                       ; 下标 +1
    loop search_loop

    ; 没找到
    mov eax, 4
    mov ebx, 1
    mov ecx, notfound_msg
    mov edx, notfound_len
    int 0x80
    jmp exit

found:
    ; 找到了(esi 是下标)
    mov eax, 4
    mov ebx, 1
    mov ecx, found_msg
    mov edx, found_len
    int 0x80

    ; 将下标转为 ASCII 字符输出
    add esi, '0'                  ; 单数字下标转字符
    push esi                      ; 压栈作为临时存储
    mov eax, 4
    mov ebx, 1
    mov ecx, esp                  ; 栈顶地址
    mov edx, 1
    int 0x80
    pop esi

    ; 输出换行
    mov eax, 4
    mov ebx, 1
    mov ecx, newline
    mov edx, 1
    int 0x80

exit:
    mov eax, 1
    mov ebx, 0
    int 0x80

二维数组

二维数组在内存中按行展开为一维存储。访问 arr[i][j] 的地址公式为:

地址 = 基址 + (i*列数 + j) * 元素大小

实例

; 文件路径:2d_array.asm
; 二维数组的定义和访问

section .data
    ; 3 行 4 列的二维数组
    matrix dd 1,  2,  3,  4
           dd 5,  6,  7,  8
           dd 9, 10, 11, 12

    rows equ 3
    cols equ 4
    elem_size equ 4              ; 双字 = 4 字节

section .text
    global _start

_start:
    ; 访问 matrix[1][2] = 7(第2行第3列)
    ; 地址 = matrix + (1*4 + 2) * 4 = matrix + 24

    mov eax, [matrix + (1 * cols + 2) * elem_size]
    ; eax = 7

    ; 使用寄存器动态计算(假设 i=2, j=1)
    ; matrix[2][1] = 10(第3行第2列)
    mov esi, 2                   ; 行 i = 2
    mov edi, 1                   ; 列 j = 1

    mov eax, cols                ; 列数
    mul esi                      ; eax = i * cols = 2*4 = 8
    add eax, edi                 ; eax = i*cols + j = 8+1 = 9
    ; eax = eax * elem_size
    ; 注意:MUL 的结果在 EAX 中,这里直接使用
    mov eax, [matrix + eax * elem_size]
    ; eax = 10

    ; 遍历二维数组所有元素
    mov ecx, rows * cols         ; 总元素数 = 12
    mov esi, 0                   ; 下标
    mov ebx, 0                   ; 累加和

traverse:
    add ebx, [matrix + esi * elem_size]
    inc esi
    loop traverse
    ; ebx = 1+2+3+...+12 = 78

    mov eax, 1
    int 0x80

冒泡排序完整示例

实例

; 文件路径:bubble_sort.asm
; 冒泡排序算法

section .data
    array dd 64, 34, 25, 12, 22, 11, 90, 78
    array_len equ ($ - array) / 4

section .text
    global _start

_start:
    mov ecx, array_len            ; 外层循环:n 次
    dec ecx                       ; 外层只需 n-1 次

outer_loop:
    push ecx                      ; 保存外层计数器

    mov esi, 0                    ; 内层下标从 0 开始
    mov ecx, array_len - 1        ; 内层循环次数

inner_loop:
    mov eax, [array + esi * 4]    ; a[j]
    mov ebx, [array + esi * 4 + 4]  ; a[j+1]
    cmp eax, ebx                  ; a[j] > a[j+1] ?
    jle no_swap                   ; 否,不交换

    ; 交换 a[j] 和 a[j+1]
    mov [array + esi * 4], ebx
    mov [array + esi * 4 + 4], eax

no_swap:
    inc esi
    loop inner_loop

    pop ecx
    loop outer_loop
    ; 数组现在已排序:11, 12, 22, 25, 34, 64, 78, 90

    mov eax, 1
    mov ebx, 0
    int 0x80

汇编语言中的数组没有任何边界检查。访问越界的索引不会报错,而是会静默地读写邻近内存中的数据,这可能导致难以调试的 bug。务必自己确保索引在合法范围内。