You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

指针实现矩阵乘法异常:非方阵计算结果缺失部分值

排查基于指针的非方阵矩阵乘法问题

嘿,我明白你折腾这个指针版矩阵乘法好几周的挫败感了——方阵能正常跑,非方阵就出乱子,还没报错,这种隐式bug最磨人。咱们来一步步拆解你的代码,把问题揪出来!

核心问题:结果矩阵的行/列索引搞反了

你代码里给结果矩阵p3赋值的这行是关键bug:

*(*(p3+j)+i)=m1;

矩阵乘法的结果p3是n1行(第一个矩阵的行数)、n4列(第二个矩阵的列数)的矩阵。在你的循环里,i遍历的是p3的行(0到n1-1),j遍历的是p3的列(0到n4-1),但你把行索引i和列索引j写反了!

正确的赋值应该是:

*(*(p3+i)+j)=m1;

为什么方阵的时候没问题?因为方阵的行和列数相同(n1=n4),i和j的取值范围完全一样,所以反着存也能碰巧读出正确的值。但非方阵的话,比如2行4列的结果矩阵,j的范围是0-3,i是0-1,反着存就会把本该存在p3[0][3]的值放到p3[3][0]——这个位置不在你后续打印的n1行n4列范围内,而你打印的p3[i][j]是p3[0][0]到p3[1][3],这些位置很多都没被赋值,所以显示的是未初始化的垃圾值(比如你看到的2508544)。

次要问题:循环边界与越界访问

  1. 矩阵乘法合法性检查:你没有验证第一个矩阵的列数n2是否等于第二个矩阵的行数n3,这是矩阵乘法的必要条件。如果用户输入错误(比如2x3乘4x5),你的代码还是会强行计算,结果肯定不对。建议在读取维度后加个判断:
if(n2 != n3){
    printf("Error: 第一个矩阵的列数必须等于第二个矩阵的行数!");
    return 1;
}
  1. 中间打印的越界问题:你中间调试用的printf里,*(*(p1+i)+j)和*(*(p2+i)+j)都存在越界访问:
    • p1是n1行n2列,j的范围是0到n4-1,当n4>n2时(比如你例子里的4>3),j会超出p1的列范围,读取到随机内存的值。
    • p2是n3行n4列,i的范围是0到n1-1,当n1>n3时,i会超出p2的行范围,同样读取垃圾值。
      这个调试打印可以删掉,或者调整成只打印当前计算相关的元素,比如*(*(p1+i)+k)和*(*(p2+k)+j)。

修正后的完整代码

这里把关键修改标注出来:

#include<stdio.h>
int main(){
    int i, j, k, n1=1, n2=1, n3=1, n4=1, m1;
    int p1[11][11], p2[11][11], p3[11][11];
    printf("\n\nInput first matrix number of rows and columns : \n");
    scanf("%d %d", &n1, &n2);
    printf("\n\nInput second matrix number of rows and columns : \n");
    scanf("%d %d", &n3, &n4);

    // 新增:检查矩阵乘法合法性
    if(n2 != n3){
        printf("Error: 第一个矩阵的列数必须等于第二个矩阵的行数!");
        return 1;
    }

    printf("\n\nInput your values for the first matrix: \n");
    for(i=0; i<n1; i++){
        for(j=0; j<n2; j++){
            printf("\n Input element of Row [%d] and Colunm[%d] = ", i+1, j+1);
            scanf("%d", (*(p1+i)+j));
        }
    }
    printf("\n\nInput your values for the second matrix : \n");
    for(i=0; i<n3; i++){
        for(j=0; j<n4; j++){
            printf("\n Input element of Row [%d] and Colunm[%d] = ", i+1, j+1);
            scanf("%d", (*(p2+i)+j));
        }
    }
    printf("\n\n\n");
    for(i=0;i<n1;i++){
        for(j=0;j<n4;j++){
            m1=0;
            // k的范围用n2更清晰(已验证n2=n3)
            for(k=0;k<n2;k++){
                m1+=(*(*(p1 + i) + k)) * (*(*(p2 + k) + j));
            }
            // 修正:行i,列j的正确赋值
            *(*(p3+i)+j)=m1;
            // 修正调试打印,避免越界
            printf("计算p3[%d][%d] = %d\n", i, j, m1);
        }
    }
    printf("\n\n");
    printf("\n\nThe result is: \n\n\n\t");
    for(i=0; i<n1; i++){
        printf("\n\t");
        for(j=0; j<n4; j++){
            printf("[%d]\t", *(*(p3+i)+j));
        }
        printf("\t\n\n\n\t");
    }
    printf("\n");
    system("pause");
    return 0;
}

排查这类问题的小技巧

  • 先验证核心逻辑:把循环变量的含义写在注释里(比如i: 结果矩阵的行、j: 结果矩阵的列、k: 累加的维度),避免搞混索引对应关系。
  • 打印中间值调试:像上面那样,打印每个p3[i][j]的计算值,先确认m1是正确的,再看是不是存到了正确的位置。
  • 检查未初始化内存:如果出现随机大数值,大概率是访问了未赋值的内存,这时候要检查赋值语句的索引是否覆盖了所有需要的位置。
  • 边界条件测试:先测试小的非方阵(比如2x2*2x3),手动计算结果,对比程序输出,快速定位问题。

内容的提问来源于stack exchange,提问作者Isaac D.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:07:46