C语言动态内存实现矩阵转置乘求迹:非方阵计算错误排查
解决非方阵下
trace(transpose(matrixA)*matrixB)计算错误的问题 我看到你在计算tr(AᵀB)时,非方阵场景下结果不符合预期——复现案例中预期得到56,但实际返回18。咱们来一步步拆解代码里的问题,然后修正它。
核心问题分析
首先明确矩阵维度:
matrixA是2行3列(m=2, n=3),转置后Aᵀ是3行2列matrixB是2行3列,所以Aᵀ * B的结果是3行3列的方阵,trace是这个方阵的对角线元素之和
你的代码在转置、矩阵乘法、trace计算这三个环节都存在维度匹配错误,导致结果偏差。
1. 矩阵转置的索引错误
你分配转置矩阵的内存大小虽然数值上正确(23=32),但索引计算逻辑完全错误:
- 转置矩阵
Aᵀ的行是原矩阵的列数(3行),列是原矩阵的行数(2列),行优先存储的话,Aᵀ[j][i] = A[i][j]对应的索引应该是j * matrixARowLenght + i - 你的代码写成了
i * matrixAColLenght + j,相当于把转置矩阵当成了2行3列来存储,完全颠倒了行列关系
2. 矩阵乘法的内存分配与索引错误
- 乘积
Aᵀ*B是3×3的矩阵,需要分配3*3=9个元素的内存,但你只分配了2*3=6个,会导致内存越界 - 乘法循环中,转置矩阵的索引计算错误:
Aᵀ每行有2个元素,索引应该是i * matrixARowLenght + k,你写成了i * matrixAColLenght + k(按每行3个元素计算) - 乘积矩阵的索引也错误:3×3的矩阵每行3个元素,索引应该是
i * matrixBColLenght + j,你的代码混用了不同的维度值
3. Trace计算的循环范围错误
Trace是3×3矩阵的对角线,需要循环3次(i从0到2),但你循环了matrixARowLenght=2次,漏掉了最后一个对角线元素;同时索引计算也因之前的错误而偏离。
修正后的代码
下面是修复后的完整核心代码,我标注了关键修改点:
// 1. 修正转置矩阵的内存分配与索引逻辑 int* matrixATransposed = (int*) malloc(matrixAColLenght * matrixARowLenght * sizeof(int)); // n*m,3*2 for (int i = 0; i < matrixARowLenght; i++) { // 原矩阵的行 for (int j = 0; j < matrixAColLenght; j++) { // 原矩阵的列 // Aᵀ[j][i] = A[i][j],行优先存储:j是Aᵀ的行,i是Aᵀ的列 *(matrixATransposed + j * matrixARowLenght + i) = *(matrixA + i * matrixAColLenght + j); } } // 2. 修正乘积矩阵的内存分配与乘法逻辑 // Aᵀ是n×m,B是m×n,乘积是n×n(3×3) int* mulRes = (int*)malloc(matrixAColLenght * matrixBColLenght * sizeof(int)); // n*n,3*3 for (int i = 0; i < matrixAColLenght; i++) { // 遍历Aᵀ的行(n=3) for (int j = 0; j < matrixBColLenght; j++) { // 遍历B的列(n=3) *(mulRes + i * matrixBColLenght + j) = 0; // 乘积矩阵每行n个元素 for (int k = 0; k < matrixARowLenght; k++) { // 遍历Aᵀ的列/B的行(m=2) // Aᵀ[i][k] 的索引:i是行,每行m个元素 → i*matrixARowLenght +k // B[k][j] 的索引:k是行,每行n个元素 → k*matrixBColLenght +j *(mulRes + i * matrixBColLenght + j) += *(matrixATransposed + i * matrixARowLenght + k) * *(matrixB + k * matrixBColLenght + j); } } } // 3. 修正Trace计算的循环范围与索引 int trace = 0; // 乘积是n×n矩阵,循环n次(matrixAColLenght=3) for (int i = 0; i < matrixAColLenght; i++) { // 取对角线元素mulRes[i][i] trace += *(mulRes + i * matrixBColLenght + i); } printf_s("Sum: %d\n", trace);
验证结果
用你提供的复现命令测试:
matrixA = [[1,2,3],[4,5,6]],matrixB = [[6,5,4],[3,2,1]]Aᵀ = [[1,4],[2,5],[3,6]]Aᵀ*B = [[1*6+4*3, 1*5+4*2, 1*4+4*1], [2*6+5*3, 2*5+5*2, 2*4+5*1], [3*6+6*3, 3*5+6*2, 3*4+6*1]]
=[[18, 13, 8], [27, 20, 13], [36, 27, 18]]- Trace是18+20+18=56,和预期一致。
额外优化建议
- 用更清晰的变量名,比如把
matrixARowLenght改成m,matrixAColLenght改成n,这样维度关系更直观 - 记得在使用完malloc的内存后调用
free(),避免内存泄漏 - 可以添加维度合法性检查:当计算
Aᵀ*B时,A的行数必须等于B的行数,否则乘法无意义
内容的提问来源于stack exchange,提问作者Aviel Fedida
相关产品推荐
相关产品推荐

