【问题标题】:Segmentation fault in a recursive function递归函数中的分段错误
【发布时间】:2013-03-05 07:10:56
【问题描述】:

我正在实施Strassen's matrix multiplication algorithm 作为作业的一部分。我已经正确编码,但我不知道为什么它会给出分段错误。 我在 main 中将 strassen() 称为 strassen(0,n,0,n);。 n 是用户给定的数字,它是 2 的幂,它是矩阵(2D 数组)的最大尺寸。 对于 n = 4,它没有给出段错误,但对于 n = 8、16、32,它给出了段错误。 代码如下。

    void strassen(int p, int q, int r, int s)
    {
        int p1,p2,p3,p4,p5,p6,p7;   
        if(((q-p) == 2)&&((s-r) == 2))
        {
            p1 = ((a[p][r] + a[p+1][r+1])*(b[p][r] + b[p+1][r+1]));
            p2 = ((a[p+1][r] + a[p+1][r+1])*b[p][r]);
            p3 = (a[p][r]*(b[p][r+1] - b[p+1][r+1]));
            p4 = (a[p+1][r+1]*(b[p+1][r] - b[p][r]));
            p5 = ((a[p][r] + a[p][r+1])*b[p+1][r+1]);
            p6 = ((a[p+1][r] - a[p][r])*(b[p][r] +b[p][r+1]));
            p7 = ((a[p][r+1] - a[p+1][r+1])*(b[p+1][r] + b[p+1][r+1]));
            c[p][r] = p1 + p4 - p5 + p7;
            c[p][r+1] = p3 + p5;
            c[p+1][r] = p2 + p4;
            c[p+1][r+1] = p1 + p3 - p2 + p6;
        }
        else
        {
            strassen(p, q/2, r, s/2);
            strassen(p, q/2, s/2, s);
            strassen(q/2, q, r, s/2);
            strassen(q/2, q, s/2, s);
        }
    }

【问题讨论】:

  • 很可能终止条件不正确,并且函数递归直到溢出堆栈。您至少应该检查在调试器中运行时会发生什么。如果调试器在c 数组的其中一个分配处停止,请检查索引以确保它们没有超出范围。
  • 不要让我们猜测。段错误、堆栈溢出或超出数组边界的原因是什么?在 gdb 中敲击它并提供更多信息。
  • 您也可以尝试将int 声明放在第一个if 中。虽然我认为约阿希姆是正确的。您确定条件是== 而不是<=?假设 pq 是 10 和 10。那么我们有 (10,10) (10,5) (10,2) (10,1) (10,0) ...
  • 我将首先删除不需要的括号并在运算符周围添加一些空格。如果if(q-p < 2 && s-r < 2) 应该停止,则递归不会停止。
  • abc 来自哪里?我猜它们是全局变量,参数是数组维度。请考虑编辑您的问题以澄清这一点。不是每个人都熟悉 Strassen 的矩阵乘法算法。提供链接会很有帮助。

标签: c segmentation-fault


【解决方案1】:

else 块中的某些条件是无限递归的(至少第二个和第四个,没有检查另一个)。这可以很容易地用笔和纸证明: 例如
strassen(p, q/2, s/2, s) for `0,8,0,8 将在每次迭代中产生:

1) 0, 4, 4, 8

2) 0, 2, 4, 8

3) 0, 1, 4, 8

4) 0, 0, 4, 8

5) 0, 0, 4, 8

...

因为这些结果都没有通过你的

if(((q-p) == 2)&&((s-r) == 2))

测试,该函数将运行(我怀疑是分支,因为第 4 个函数也有同样的问题......)直到堆栈的末尾被命中,导致分段错误。

无论如何,if 您在 else 块中尝试做的是递归地平分矩阵,更好的尝试是:

strassen(p, (q+p)/2, r, (r+s)/2);                                               
strassen(p, (q+p)/2, (r+s)/2, s);                                               
strassen((q+p)/2,q, (r+s)/2, s);                                                
strassen((q+p)/2,q, r, (r+s)/2);        

(请记住,我没有检查此代码)

【讨论】:

  • 谢谢,我会再次尝试用 pen n paper 和 gdb 查看它。
  • 如果我的回答满足你的问题,请不要忘记将其标记为解决方案 ;-)
【解决方案2】:
void strassen(int p, int q, int r, int s)
{
    int p1,p2,p3,p4,p5,p6,p7;   
    if(q-p == 2 && s-r == 2)
    {
        p1 = (a[p][r] + a[p+1][r+1])   * (b[p][r] + b[p+1][r+1]);
        p2 = (a[p+1][r] + a[p+1][r+1]) * b[p][r];
        p3 = a[p][r]                   * (b[p][r+1] - b[p+1][r+1]);
        p4 = a[p+1][r+1]               * (b[p+1][r] - b[p][r]);
        p5 = (a[p][r] + a[p][r+1])     * b[p+1][r+1];
        p6 = (a[p+1][r] - a[p][r])     * (b[p][r] +b[p][r+1] );
        p7 = (a[p][r+1] - a[p+1][r+1]) * (b[p+1][r] + b[p+1][r+1]);
        c[p][r] = p1 + p4 - p5 + p7;
        c[p][r+1] = p3 + p5;
        c[p+1][r] = p2 + p4;
        c[p+1][r+1] = p1 + p3 - p2 + p6;
    }
    else
    {
        if (q/2-p >= 2 && s/2-r >= 2) strassen(p, q/2, r, s/2);
        if (q/2-p >= 2 && s-s/2 >= 2) strassen(p, q/2, s/2, s);
        if (q-q/2 >= 2 && s/2-r >= 2) strassen(q/2, q, r, s/2);
        if (q-q/2 >= 2 && s-s/2 >= 2) strassen(q/2, q, s/2, s);
    }
}

但更简单的递归停止器将位于函数的开头,例如:

{
    int p1,p2,p3,p4,p5,p6,p7;   
    if(q-p < 2 || s-r < 2) return;
    if(q-p == 2 && s-r == 2)
    { ...

【讨论】:

    猜你喜欢
    • 2014-11-05
    • 2019-11-16
    • 2017-12-25
    • 1970-01-01
    • 1970-01-01
    • 2014-04-27
    • 2022-01-12
    相关资源
    最近更新 更多