简体   繁体   English

关于在矩阵乘法中执行Strassen算法的C编程中的分段错误

[英]Segmentation fault in C programming about performing Strassen's algorithm in matrix multiplication

I am writing a code which aims to multiply two dense matrix using Strassen's Algorithm. 我正在编写一个旨在使用Strassen算法将两个密集矩阵相乘的代码。 The main code is a recursive function whose base case is when the size of the two matrix is 2x2, therefore the multiplication of the matrix is just the multiplication of real numbers. 主要代码是一个递归函数,其基本情况是两个矩阵的大小为2x2时,因此矩阵的乘法运算只是实数的乘法运算。 If the base case is not satisfied, I then compute the seven matrix used to compute the final result of multiplication by calling the recursive function again, with the size of the matrix divided by half. 如果不满足基本条件,则通过再次调用递归函数,将矩阵的大小除以一半,从而计算出用于计算乘法最终结果的七个矩阵。 However, when trying to run this code, I am getting segmentation fault, but I just can not figure out why. 但是,当尝试运行此代码时,我遇到了分段错误,但是我却无法弄清原因。 I uses the gdb debugger, seems at some point I am getting NULL temp1 and C1, but I have not idea why this is happening. 我使用了gdb调试器,似乎在某些时候我得到了NULL temp1和C1,但是我不知道为什么会这样。 Also, the counter I used in for loop gets way beyond there limit(they should be restrained within n/2). 另外,我在for循环中使用的计数器超出了限制(它们应限制在n / 2以内)。 Finally, is this the right way to perform Strassen's algorithm recursively? 最后,这是递归执行Strassen算法的正确方法吗? Here is my code. 这是我的代码。

#include "assignment2.h"

void denseMatrixMult(int ** A, int ** B, int *** resultMatrix, int n)
{
     if(n==2)
     {
        int M0,M1,M2,M3,M4,M5,M6;
        M0=(A[0][0]+A[1][1])*(B[0][0]+B[1][1]);
        M1=(A[1][0]+A[1][1])*B[0][0];
        M2=A[0][0]*(B[0][1]-B[1][1]);
        M3=A[1][1]*(B[1][0]-B[0][0]);
        M4=(A[0][0]+A[0][1])*B[1][1];
        M5=(A[1][0]-A[0][0])*(B[0][0]+B[0][1]);
        M6=(A[0][1]-A[1][1])*(B[1][0]+B[1][1]);
        int** temp;
        initMatrix(&temp,2);
        resultMatrix=&temp;
        *(resultMatrix)[0][0]=M0+M3-M4+M6;
        *(resultMatrix)[0][1]=M2+M4;
        *(resultMatrix)[1][0]=M1+M3;
        *(resultMatrix)[1][1]=M0-M1+M2+M5;
        /*free(freeMatrix(temp);*/
        return;
     }
     else
     {
         int a,b,c,d,e,f,g,h;
         int** N0;
         int** N1;
         int** N2;
         int** N3;
         int** N4;
         int** N5;
         int** N6;
         int** zero;
         int** C1;
         int** C2;
         int** C3;
         int** C4;
         initMatrix(&N0,n/2);
         initMatrix(&N1,n/2);
         initMatrix(&N2,n/2);
         initMatrix(&N3,n/2);
         initMatrix(&N4,n/2);
         initMatrix(&N5,n/2);
         initMatrix(&N6,n/2);
         initMatrix(&zero,n/2);
         denseMatrixMult(sum(A,A,0,0,n/2,n/2,n/2),sum(B,B,0,0,n/2,n/2,n/2),&N0,n/2);
         denseMatrixMult(sum(A,A,n/2,0,n/2,n/2,n/2),sum(B,zero,0,0,0,0,n/2),&N1,n/2);
         denseMatrixMult(sum(A,zero,0,0,0,0,n/2),sub(B,B,0,n/2,n/2,n/2,n/2),&N2,n/2);
         denseMatrixMult(sum(A,zero,n/2,n/2,0,0,n/2),sub(B,B,n/2,0,0,0,n/2),&N3,n/2);
         denseMatrixMult(sum(A,A,0,0,0,n/2,n/2),sum(B,zero,n/2,n/2,0,0,n/2),&N4,n/2);
         denseMatrixMult(sub(A,A,n/2,0,0,0,n/2),sum(B,B,0,0,0,n/2,n/2),&N5,n/2);
         denseMatrixMult(sub(A,A,0,n/2,n/2,n/2,n/2),sum(B,B,n/2,0,n/2,n/2,n/2),&N6,n/2);
         C1=sum(sub(sum(N0,N3,0,0,0,0,n/2),N4,0,0,0,0,n/2),N6,0,0,0,0,n/2);
         C2=sum(N2,N4,0,0,0,0,n/2);
         C3=sum(N1,N3,0,0,0,0,n/2);
         C4=sum(sum(sub(N0,N1,0,0,0,0,n/2),N2,0,0,0,0,n/2),N5,0,0,0,0,n/2);
         int** temp1;
         initMatrix(&temp1,n);
         resultMatrix=&temp1;
         for(a=0;a<n/2;a++)
         {
             for(b=0;b<n/2;b++)
             {
                 (*resultMatrix)[a][b]=C1[a][b];
             }
         }
         for(c=n/2;c<n;c++)
         {
             for(d=0;d<n/2;d++)
             {
                 (*resultMatrix)[c][d]=C3[c-n/2][d];
             }
         }
         for(e=0;e<n/2;e++)
         {
             for(f=n/2;f<n;f++)
             {
                 (*resultMatrix)[e][f]=C2[e][f-n/2];
             }
         }
         for(g=n/2;g<n;g++)
         {
             for(h=n/2;h<n;h++)
             {
                 (*resultMatrix)[g][h]=C4[g-n/2][h-n/2];
             }
          }
          /*freeMatrix(N0);
          freeMatrix(N1);
          freeMatrix(N2);
          freeMatrix(N3);
          freeMatrix(N4);
          freeMatrix(N5);
          freeMatrix(N6);
          freeMatrix(C1);
          freeMatrix(C2);
          freeMatrix(C3);
          freeMatrix(C4);*/


     }
}
int **sum(int ** A, int ** B, int x1, int y1, int x2, int y2, int n)
{
    int i,j,k;

    int ** res=(int**)malloc(n*sizeof(int*));
    if(res!=NULL)
    {
       for(i=0;i<n;i++)
       {
          res[i]=(int*)malloc(n*sizeof(int));
       }

       for(j=0;j<n;j++)
       {
           for(k=0;k<n;k++)
           {
               res[j][k]=A[x1+j][y1+k]+B[x2+j][y2+k];
           }
       }
    }
    return res;

}
int **sub(int **A, int **B, int x1, int y1, int x2, int y2, int n)
{
    int i,j,k;

    int ** res=(int**)malloc(n*sizeof(int*));
    if(res!=NULL)
    {
       for(i=0;i<n;i++)
       {
          res[i]=(int*)malloc(n*sizeof(int));
       }

       for(j=0;j<n;j++)
       {
           for(k=0;k<n;k++)
           {
               res[j][k]=A[x1+j][y1+k]-B[x2+j][y2+k];
           }
       }
    }
    return res;
}
void initMatrix(int ***mat,int n)
{
    int i,j,k;
    int ** Mat=(int**)malloc(n*sizeof(int*));
    for(i=0;i<n;i++)
    {
        Mat[i]=(int*)malloc(n*sizeof(int));
    }
    for(j=0;i<n;i++)
    {
        for(k=0;k<n;i++)
        {
            Mat[j][k]=0;
        }
    }
    *mat=Mat;
}

int **readMatrix(char * filename)
{
    int i,j,k;
    int **mat=(int**)malloc(MATSIZE*sizeof(int*));
    for(i=0;i<MATSIZE;i++)
    {
        mat[i]=(int*)malloc(MATSIZE*sizeof(int));
    }
    FILE *fp=fopen(filename,"r");
    for(j=0;j<MATSIZE;j++)
    {
        for(k=0;k<MATSIZE;k++)
        {
            fscanf(fp,"%d",&mat[j][k]);
        }
    }
    fclose(fp);
    return mat;

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

void printMatrix(int n, int ** A)
{
     int i,j;
     for(i=0;i<n;i++)
     {
         for(j=0;j<n;j++)
         {
             printf("%d",A[i][j]);
         }
     }
}
#include "assignment2.h"

void p1(void)
{
    int **matrix;
    initMatrix(&matrix,MATSIZE);
    printMatrix(MATSIZE,matrix);
    freeMatrix(MATSIZE, matrix);
}

void p2(void)
{
    int ** matrix1=readMatrix("matrix1.txt");
    printMatrix(MATSIZE,matrix1);
    freeMatrix(MATSIZE, matrix1);
}

void p3a(void)
{
    int ** matrix1=readMatrix("matrix1.txt");
    int ** matrix2=readMatrix("matrix2.txt");
    int ** sumMatrix = sum(matrix1, matrix2, 1, 1, 0, 1, 3);
    printMatrix(MATSIZE,matrix1);
    printMatrix(MATSIZE,matrix2);
    printMatrix(3,sumMatrix);
    freeMatrix(MATSIZE, matrix1);
    freeMatrix(MATSIZE, matrix2);
    freeMatrix(3, sumMatrix);
}

void p3b(void)
{
    int ** matrix1=readMatrix("matrix1.txt");
    int ** matrix2=readMatrix("matrix2.txt");
    int ** subMatrix = sub(matrix1, matrix2, 1, 1, 0, 1, 3);
    printMatrix(MATSIZE,matrix1);
    printMatrix(MATSIZE,matrix2);
    printMatrix(3,subMatrix);
    freeMatrix(MATSIZE, matrix1);
    freeMatrix(MATSIZE, matrix2);
    freeMatrix(3, subMatrix);
}

void p4(void)
{
    char dataFileMat1[]="matrix1.txt";
    char dataFileMat2[]="matrix2.txt";
    int ** matrix1=readMatrix(dataFileMat1);
    int ** matrix2=readMatrix(dataFileMat2);
    int ** resultingMatrix;
    denseMatrixMult(matrix1, matrix2, &resultingMatrix, MATSIZE);
    printMatrix(MATSIZE,resultingMatrix);
    freeMatrix(MATSIZE,resultingMatrix);
    freeMatrix(MATSIZE,matrix1);
    freeMatrix(MATSIZE,matrix2);
}

int main( int argc, char *argv[] )
{
    if( argc < 2 )
    {
        printf("Expecting at least one argument. Please try again\n");
    }
    else if(argc==2)
    {
        if(atoi(argv[1])==3)
        {
            printf("Expecting two arguments for this part. Please try again.\n");
        }
        else
        {
            if(atoi(argv[1])==1)
            {
                p1();
            }
            else if(atoi(argv[1])==2)
            {
                p2();
            }
            else if(atoi(argv[1])==4)
            {
                p4();
            }
            else
            {
                printf("Incorrect argument supplied.\n");
            }
        }
    }
    else if(argc==3)
    {
        if(atoi(argv[1])!=3)
        {
            printf("Expecting two arguments only for Part 3. Please try again.\n");
        }
        else
        {
            if(atoi(argv[2])==1)
            {
                p3a();
            }
            else if(atoi(argv[2])==2)
            {
                p3b();
            }
        }
    }
    else
    {
        printf("The argument supplied is %s\n", argv[1]);
    }
}

The failing free lets suspect that the heap management is corrupted. free的失败使人们怀疑堆管理已损坏。 Possible reason for this is out of range write access to allocated memory. 可能的原因是超出了对分配内存的写访问范围。 Why don't you simplify the allocation of matrices? 您为什么不简化矩阵的分配?

There is only one malloc() necessary to allocate. 仅需要分配一个malloc() For this you may allocate an one-dimensional array of appropriate size. 为此,您可以分配一个适当大小的一维数组。

  1. You may use the allocated array to store matrix elements (row for row) consecutively. 您可以使用分配的数组连续存储矩阵元素(逐行)。 Read and write accesses has to be done in form i * N + j ( i ... row index, j ... column index, N ... number of columns). 读写访问必须以i * N + j形式进行( i ...行索引, j ...列索引, N ...列数)。
  2. You may apply some C-cast-magic and can even use it as two dimensional array. 您可以应用一些C-cast-magic,甚至可以将其用作二维数组。

I prepared a small sample to demonstrate this: 我准备了一个小样本来证明这一点:

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

enum { N = 4 };

int main(int argc, char **argv)
{
  int i, n;
  /* allocation of an array with size NxN: */
  double *arr = (double*)malloc(N * N * sizeof (double));
  /* initialization of array (with some illustrative values) */
  for (i = 0, n = N * N; i < n; ++i) {
    int row = i / N, col = i % N;
    arr[i] = (double)(row + col * 0.1);
  }
  /* show contents */
  printf("arr[]:\n");
  for (i = 0; i < N; ++i) {
    int j;
    for (j = 0; j < N; ++j) {
      printf("%s%.1f", j ? "\t" : "", arr[i * N + j]);
    }
    printf("\n");
  }
  /* how this is used as two-dimensional array */
  { double (*mat)[N] = (double(*)[N])arr;
    printf("mat[][]:\n");
    for (i = 0; i < N; ++i) {
      int j;
      for (j = 0; j < N; ++j) {
        printf("%s%.1f", j ? "\t" : "", mat[i][j]);
      }
      printf("\n");
    }
  }
  /* clean-up */
  free(arr);
  /* done */
  return 0;
}

Compiled and tested with gcc on cygwin: 在cygwin上用gcc编译和测试:

$ gcc -o test-mat test-mat.c

$ ./test-mat
arr[]:
0.0     0.1     0.2     0.3
1.0     1.1     1.2     1.3
2.0     2.1     2.2     2.3
3.0     3.1     3.2     3.3
mat[][]:
0.0     0.1     0.2     0.3
1.0     1.1     1.2     1.3
2.0     2.1     2.2     2.3
3.0     3.1     3.2     3.3

The type double (*)[N] has to be read as "address of a one-dimensional array with size N". 类型double (*)[N]必须被读取为“大小为N的一维数组的地址”。 The parentheses may look surprising but are necessary. 括号可能看起来令人惊讶,但是是必需的。 (Without, the compiler would read this as "one-dimensional array of addresses" what's not my intention.) (没有编译器会将其读为“一维地址数组”,这不是我的意图。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM