【问题标题】:Calloc() error force closing program, invisible to debugger [closed]Calloc()错误强制关闭程序,调试器不可见[关闭]
【发布时间】:2018-07-22 06:21:39
【问题描述】:

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

  1. 指向矩阵 A 的指针
  2. a_rows,A 中的行数
  3. a_cols A 中的列数
  4. 指向矩阵 B 的指针
  5. b_cols,B 中的列数

由于产品将具有与 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;
}

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

让我感到奇怪的是,当我将“a_rows”和“b_cols”更改为常数(例如,20)时,函数运行正常。什么可能导致这个问题?以及如何解决?任何帮助将不胜感激。

【问题讨论】:

  • 你所有的内存分配都被破坏了:你将错误的类型传递给sizeof,你不应该转换calloc()
  • 从不初始化a_rows,b_cols...

标签: c matrix-multiplication


【解决方案1】:

您的代码错误。 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整体的分配,在实践中所有指针的大小都是一样的,所以sizeof(double**)一般是一样的值(我的Linux/x86-64上8字节)比sizeof(double*).

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

顺便说一句,拥有矩阵的更好方法是使它们成为一些抽象数据类型,例如here

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

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

【讨论】:

  • 这是一个指向抽象数据解决方案的良好链接。:)
【解决方案2】:

您分配了错误的内存量。

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

这会为双指针的b_cols 分配内存,而不是双指针的b_cols

这是使用typedef(&lt;type&gt;)时的典型错误,非常容易出错 很容易,因为您在不需要的地方添加了*,或者您忘记在需要时添加*

使用sizeof *var 比使用sizeof(&lt;type&gt;) 更好:

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 未定义行为的指针,将导致段错误。也不要 之后忘记释放内存。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多