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

C语言行列式计算程序结果错误与内存泄漏问题排查

行列式计算程序Bug修复说明

程序同时存在内存操作错误、逻辑实现错误两类问题,直接导致计算结果偏差、内存越界和泄漏,具体问题和修复方式如下:

已定位的Bug列表

  • 内存分配类型不匹配:findminor中为矩阵行申请内存时,错误使用sizeof(double*)(指针长度)作为单位,应当使用sizeof(double)(双精度浮点数长度),跨平台运行时会出现内存分配不足的问题。
  • 余子式遍历索引越界:findminor中列索引变量c仅在函数开头初始化为0,每遍历完一行后没有重置为0,遍历后续行时c的值已经超过矩阵列索引上限,触发Valgrind报告的非法内存读错误。
  • 无意义内存分配导致泄漏:compute_det开头提前申请了double** minor = malloc(n * sizeof(double*)),但后续循环中直接将minor指针指向findminor返回的新地址,初始申请的内存没有被释放也没有被引用,是Valgrind报告的88字节内存泄漏的直接来源。
  • 递归传参错误:递归计算余子式行列式时,错误传入阶数n - 1 - i,余子式固定为n-1阶,和当前展开的列号i无关,这个错误直接导致高阶余子式被低阶计算,结果完全错误。
  • 返回值逻辑错误:使用整数绝对值函数abs()处理浮点结果,一方面会丢失浮点精度,另一方面强行取绝对值会抹掉行列式的合法负数值;且abs()接收int类型参数,传入double会触发隐式类型转换,进一步引入计算误差。
  • 输入格式串冗余:scanf的格式串"%lf "末尾多了一个空格,会强制scanf持续读取空白字符直到遇到非空白输入,导致输完所有矩阵元素后程序不会立刻继续执行,需要额外输入任意字符才会输出结果,这也是Valgrind输出中出现莫名的15输入的原因。

修复方式

  1. 重写findminor的余子式生成逻辑,去掉容易出错的手动列索引计数,直接通过位置映射生成余子式:余子式第i行对应原矩阵第i+1行(固定去掉第0行做展开),余子式第j列对应原矩阵第j < flag ? j : j+1列(跳过第flag列),从根源避免索引越界。
  2. 删除compute_det开头无意义的minor初始内存分配,直接在循环内接收findminor返回的指针即可。
  3. 修正递归调用参数,余子式计算固定传入阶数n-1。
  4. 去掉返回值的abs()调用,直接返回计算得到的带符号结果;如果业务场景确实需要绝对值,使用浮点版本的fabs()函数。
  5. 去掉scanf格式串末尾的多余空格。

修复后可运行代码

#include <stdio.h>
#include <stdlib.h>

double** findminor(double** a, int n, int flag) {
    double** minor = malloc((n - 1) * sizeof(double*));
    for (int i = 0; i < n - 1; i++) {
        // 修正内存分配单位为double
        minor[i] = malloc((n - 1) * sizeof(double));
        for (int j = 0; j < n - 1; j++) {
            // 直接映射原矩阵位置,无需维护单独的列索引变量
            int src_col = j < flag ? j : j + 1;
            minor[i][j] = a[i+1][src_col];
        }
    }
    return minor;
}

void freeMinor(double** minor, int n) {
    for (int i = 0; i < n - 1; i++) {
        free(minor[i]);
    }
    free(minor);
}

double compute_det(double** a, int n) {
    if (n == 1) {
        return a[0][0];
    }
    
    double result = 0.0;
    double sign = 1.0;
    // 删除开头无意义的malloc,避免内存泄漏
    for (int i = 0; i < n; i++) {
        double** minor = findminor(a, n, i);
        // 修正递归传参,余子式固定为n-1阶
        result += sign * a[0][i] * compute_det(minor, n - 1);
        sign = -sign;
        freeMinor(minor, n);
    }
    // 去掉错误的整数绝对值调用,返回真实带符号结果
    return result;
}

void freeMatrix(double** a, int n) {
    for (int i = 0; i < n; i++) {
        free(a[i]);
    }
    free(a);
}

int main(void) {
    int n;
    printf("Input dimensions: ");
    scanf("%d", &n);
    double** a = malloc(n * sizeof(double*));

    for (int i = 0; i < n; i++) {
        a[i] = malloc(n * sizeof(double));
        for (int j = 0; j < n; j++) {
            // 去掉格式串末尾的多余空格
            scanf("%lf", &a[i][j]);
        }
    }
    
    printf("%.lf\n", compute_det(a, n));
    freeMatrix(a, n);

    return 0;
}

验证结果

使用提供的4阶测试用例输入,修复后的程序输出计算结果为-105,和数学计算结果一致(提到的正确结果105为绝对值,该行列式本身带负号);Valgrind检测无非法内存读写、无内存泄漏。

内容的提问来源于stack exchange,提问作者James Andrews

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 11:24:22