Calloc()错误强制关闭程序,对调试器不可见

时间:2018-02-12 06:05:07

标签: c heap matrix-multiplication

我正在尝试实现一个将两个动态矩阵(AxB)相乘的函数,并返回一个指向动态分配的产品(C)的指针。该函数的参数是:

  1. 指向矩阵A的指针
  2. a_rows,A
  3. 中的行数
  4. a_cols A
  5. 中的列数
  6. 指向矩阵B的指针
  7. b_cols,B中的列数
  8. 由于产品的行数与A的行数和B的列数相同,因此使用a_rows和b_cols来确定要分配的产品的大小。

    功能如下所示:

    double** MatrixMultiply(
        double** a,
        const uint32_t a_rows,
        const uint32_t a_cols,
        double** b,
        const uint32_t b_cols) {
    
        double** c;
        c = (double**) calloc(a_rows, sizeof(double**));  //product matrix C has 
        //matrix A rows and Matrix B cols
    
        for(int32_t i = 0; i < a_rows; i++) {
            c[i] = (double*) calloc(b_cols, sizeof(double*));
        }
    
        for(uint32_t i = 0; i < a_rows; i++) {
            for(uint32_t j = 0; j < b_cols; j++) {
                for(uint32_t k = 0; k < a_cols; k++) {
                    c[i][j] += a[i][k] * b[k][j];
                }
            }
        }
        return c;
    }
    

    问题在于,每当我运行程序时,它都会被函数崩溃,因为我认为是某种分段错误。但是,每当我运行调试器并逐步执行每一行时,它都不会显示已发生任何错误。

    对我来说,奇怪的是当我改变&#34; a_rows&#34;和&#34; b_cols&#34;对于常数(例如,20),该函数正确运行。什么可能导致这个问题?它怎么能修复?任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:4)

您正在分配错误的内存量。

c[i] = (double*) calloc(b_cols, sizeof(double*));

这为b_cols个双指针分配内存,而不是b_cols个双精度。

这是使用typedef(<type>)时的典型错误,一个人犯了错误 很简单,因为您在不需要的地方添加*,或者在需要时忘记添加*

最好使用sizeof *var而不是sizeof(<type>)

int *arr = malloc(size * sizeof *arr);

sizeof *arr无论类型如何都返回确切的字节数。它 也有好处,如果你以后碰巧改变了类型 变量,你不必担心改变里面的表达式 sizeof

正确的方法是:

c = calloc(a_rows, sizeof *c);

if(c == NULL)
{
    // error handling
}

for(int32_t i = 0; i < a_rows; i++) {
    c[i] = calloc(b_cols, sizeof *c[i]);
    if(c[i] == NULL)
    {
        // error handling
    }
}

同样don't cast malloc并始终检查结果是否为NULL。如果 您没有检查结果是NULL,那么您将尝试访问NULL 指针是未定义的行为,将导致段错误。也没有 忘记之后释放记忆。

答案 1 :(得分:3)

你的代码错了。 calloc(和malloc)可能会失败,你总是应该处理它。你不需要强制转换它,第二个参数是每个单元格的大小(不是指向它的指针)。

你应该有的最小值

double** c=  calloc(a_rows, sizeof(double*));
if (c==NULL) { perror("calloc c"); exit(EXIT_FAILURE); }

同样

c[i] = calloc(b_cols, sizeof(double));
if (c[i]==NULL) { perror("calloc c row"); exit(EXIT_FAILURE); };

请注意,对于每个calloc,第二个参数是一个单元格的大小(不是指向它的指针)。第一个参数是单元格的数量(您确定要b_cols,而不是a_cols吗?只有您可以知道。

对于c作为一个整体的分配,在 practice 中,所有指针的大小都相同,因此sizeof(double**)通常是相同的值(我的Linux上的8个字节/ x86-64)而不是sizeof(double*)

您应该编译所有警告和调试信息:gcc -Wall -Wextra -g。一些编译器(GCC的最新版本)可能已经警告过你。您可以使用valgrind来运行(带有检查)您的程序(可能已检测到缓冲区溢出)。当然你也应该use the gdb debugger

BTW,一种更好的矩阵方法是使它们成为像here这样的抽象数据类型。

  

但是,每当我运行调试器并逐步执行每一行时,它都不会显示已发生任何错误。

在Linux(或MacOSX)上,您可以设置系统以便进行核心转储(确保核心文件有足够大的限制,可能内置ulimit bash }),并用gdb分析核心转储的后验;见core(5)gdb(1)signal(7)。并且gdb能够运行您的程序直到它崩溃。