C与汇编混合编程生成矩阵时对角线赋值错误问题排查
问题排查与修正方案
核心问题分析
- 内存结构不匹配:你在C代码中分配的是分散的二维指针数组(每行单独通过
malloc分配,内存地址不连续),但fillMatrix函数声明和汇编代码都将其当作连续的一维数组处理,直接导致指针访问逻辑完全错误。 - 打印逻辑错误:最后打印矩阵时使用
matrix[i * n + j],这是连续一维数组的访问方式,不适用于二维指针数组,正确写法应为matrix[i][j]。 - 汇编寻址错误:汇编中直接操作
r9(int**类型)时,用r10*8偏移是访问指针数组的元素(x64下指针占8字节),而非矩阵的int元素(占4字节);同时副对角线的索引计算逻辑完全错误。
修正方案
方案1:改为连续内存的一维数组(推荐,适配汇编高效处理)
将矩阵改为连续分配的一维数组,简化汇编寻址逻辑,避免二维指针的复杂操作。
修正后的C代码
#include <stdio.h> #include <stdlib.h> extern void fillMatrix(int n, int* matrix); int main() { SetConsoleOutputCP(1251); int n; printf("Введите размерность матрицы: "); #pragma warning(suppress : 4996) scanf("%d", &n); // 分配连续的一维数组模拟二维矩阵 int* matrix = (int*)malloc(n * n * sizeof(int)); if (matrix == NULL) { printf("Ошибка выделения памяти.\n"); return 1; } printf("Сгенерированная матрица до вызова функции на ассемблере:\n"); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { matrix[i * n + j] = rand() % 100; printf("%d ", matrix[i * n + j]); } printf("\n"); } fillMatrix(n, matrix); printf("Сгенерированная матрица:\n"); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { printf("%d ", matrix[i * n + j]); } printf("\n"); } free(matrix); return 0; }
修正后的汇编代码
.CODE fillMatrix PROC ; rcx = n, rdx = 连续一维数组的起始指针 mov r8, rcx ; 保存矩阵尺寸n到r8 mov r9, rdx ; 保存矩阵起始地址到r9 xor r10, r10 ; 初始化循环索引i为0 fill_loop: cmp r10, r8 jge end_fill ; 当i >=n时退出循环 ; 处理主对角线:matrix[i*n + i] = 1 mov rax, r10 imul rax, r8 ; rax = i * n add rax, r10 ; rax = i*n + i mov dword ptr [r9 + rax*4], 1 ; int占4字节,偏移量*4 ; 处理副对角线:matrix[i*n + (n-1 -i)] = 1 mov rax, r10 imul rax, r8 ; rax = i * n mov r11, r8 dec r11 ; r11 = n-1 sub r11, r10 ; r11 = n-1 -i add rax, r11 ; rax = i*n + (n-1 -i) mov dword ptr [r9 + rax*4], 1 inc r10 jmp fill_loop end_fill: ret fillMatrix ENDP END
方案2:保留二维指针数组(适配原内存结构)
若需保留原二维指针数组的内存分配方式,需修改汇编代码,先获取每行的指针再访问对应元素。
修正后的C代码
#include <stdio.h> #include <stdlib.h> extern void fillMatrix(int n, int** matrix); int main() { SetConsoleOutputCP(1251); int n; printf("Введите размерность матрицы: "); #pragma warning(suppress : 4996) scanf("%d", &n); int** matrix = (int**)malloc(n * sizeof(int*)); if (matrix == NULL) { printf("Ошибка выделения памяти.\n"); return 1; } for (int i = 0; i < n; i++) { matrix[i] = (int*)malloc(n * sizeof(int)); if (matrix[i] == NULL) { printf("Ошибка выделения памяти.\n"); return 1; } } printf("Сгенерированная матрица до вызова функции на ассемблере:\n"); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { matrix[i][j] = rand() % 100; printf("%d ", matrix[i][j]); } printf("\n"); } fillMatrix(n, matrix); printf("Сгенерированная матрица:\n"); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { printf("%d ", matrix[i][j]); // 修正为二维指针的正确访问方式 } printf("\n"); } // 释放内存 for (int i = 0; i < n; i++) { free(matrix[i]); } free(matrix); return 0; }
修正后的汇编代码
.CODE fillMatrix PROC ; rcx = n, rdx = 二维指针数组的起始地址(int**) mov r8, rcx ; 保存矩阵尺寸n到r8 mov r9, rdx ; 保存指针数组地址到r9 xor r10, r10 ; 初始化循环索引i为0 fill_loop: cmp r10, r8 jge end_fill ; 处理主对角线:matrix[i][i] = 1 mov rax, [r9 + r10*8] ; 获取第i行的指针(x64下指针占8字节) mov dword ptr [rax + r10*4], 1 ; 访问第i行的第i个int元素(int占4字节) ; 处理副对角线:matrix[i][n-1 -i] = 1 mov r11, r8 dec r11 ; r11 = n-1 sub r11, r10 ; r11 = n-1 -i mov dword ptr [rax + r11*4], 1 ; 访问第i行的对应副对角线元素 inc r10 jmp fill_loop end_fill: ret fillMatrix ENDP END
关键错误总结
- 内存结构不匹配:二维指针数组与连续一维数组的寻址逻辑完全不同,不能混用。
- 数据宽度混淆:x64架构下指针占8字节,
int占4字节,汇编偏移计算需对应正确类型的宽度。 - 副对角线索引错误:原代码未正确计算副对角线的列索引,正确公式为
n-1 -i。
内容的提问来源于stack exchange,提问作者Alexander Smyatskikh
相关产品推荐
相关产品推荐

