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

