Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to transpose a matrix in C? - error

I am trying to write a function to transpose matrices.

paramters of that function:

  • the matrix to transpose

  • the output matrix which is empty.

The problem is I am able to transpose some matrices but some other fail like the one i am giving in my example. WHy? how could I solve it?

code:

int main (void)
{

//this works well
/*  double array[3][2] = {{1,2},{3,4},{5,6}};
    height = 3;
    width = 2;
*/
//this input doesn't work

    double array[2][3] = {{1,2,3},{4,5,6}};
    height = 2;
    width = 3;


int heightOutput =  width; //2
int widthOutput = height; //3

    double **output;

    output = malloc(widthOutput * sizeof(double *)); //rows from 1
    for (i = 0; i < widthOutput; i++)
    {
        output[i] = malloc(heightOutput * sizeof(double)); //columns
    }

    transposeMatrix(&array[0][0], height,width, &output[0][0], heightOutput, widthOutput);

            printf("\n");
            printf("\noutput matrix\n");
    for(i=0;i<heightOutput;i++)
    {
        for(j=0;j<widthOutput;j++)
        {
            printf("%f\t",output[i][j]);
        }
        printf("\n");
    }
}



void transposeMatrix(double* array2, int height, int width, double * output, int height2, int width2)
{


    double workaround[3][3] ={0};
    double result;
    int i,j;

printf("input matrix:\n");


for(i=0;i<height;i++)
    {
        for(j=0;j<width;j++)
        {
                printf("%f\t",(*((array2+i*width)+j)));

        }
        printf("\n");
    }


        printf("\n");
    for(i=0;i<width2;i++)
    {
        for(j=0;j<height2;j++)
        {
            result = (*((array2+i*width)+j));
            workaround[i][j] = result;
        }
    }


    for(i=0;i<width2;i++)
    {
        for(j=0;j<height2;j++)
        {
            *((output+j*3)+i) = workaround[i][j];
            printf("%f\t",(*((output+j*3)+i)));
        }
        printf("\n");
    }


}
like image 595
LandonZeKepitelOfGreytBritn Avatar asked Apr 24 '15 01:04

LandonZeKepitelOfGreytBritn


1 Answers

The main problem is that you confused with sizes of matrices.

  1. When you fill workaround matrix your loop should be like this, since size of original matrix is (height x width).

    for(i=0;i<width;i++)
    {
        for(j=0;j<height;j++)
        {
            result = (*((array2+i*width)+j));
            workaround[i][j] = result;
        }
    }
    
  2. When transposing matrix

    for(i=0;i<height2;i++)
    {
        for(j=0;j<width2;j++)
        {
           *((output+i*width2)+j) = workaround[j][i];
           printf("%f\t",(*((output+i*width2)+j)));
        }
    }
    
  3. In memory allocation you also got wrong sizes, it should be

    output = malloc(heightOutput * sizeof(double *)); //rows from 1
    for (i = 0; i < heightOutput; i++)
    {
        output[i] = malloc(widthOutput * sizeof(double)); //columns
    }
    

    With this changes your program will run without errors, but output is still wil be wrong

    input matrix:                                                                                                                                                                    
    1.000000        2.000000        3.000000                                                                                                                                         
    4.000000        5.000000        6.000000                                                                                                                                         
    
    1.000000        2.000000        3.000000                                                                                                                                         
    4.000000        5.000000        6.000000                                                                                                                                         
    
    
    output matrix                                                                                                                                                                    
    1.000000        4.000000                                                                                                                                                         
    5.000000        0.000000                                                                                                                                                         
    0.000000        0.000000  
    
  4. The last problem is with argument passing. You dynamically allocate memory, pointers to rows first

    output = malloc(heightOutput * sizeof(double *)); //rows from 1
    

    With this you got array of pointers

    * -> NULL
    * -> NULL
    * -> NULL
    

    and with loop you assign values to them

    for (i = 0; i < heightOutput; i++)
    {
        output[i] = malloc(widthOutput * sizeof(double)); //columns
    }
    
    * -> [e00, e01]
    * -> [e10, e11]
    * -> [e20, e21]
    

    But there is no guarantee that they will be allocated one after another, still you operate with output like with linear allocated data. To correctly work with this you need to pass double pointer.

    void transposeMatrix(double* array2, int height, int width, double ** output, int height2, int width2)
    {
        ...
        for(i=0;i<width2;i++)
        {
            for(j=0;j<height2;j++)
            {
                output[j][i] = workaround[i][j];
                printf("%f\t",output[j][i]);
            }
            printf("\n");
        }
    }
    

    If you want to allocate memory linear do it like follows

    output = malloc(heightOutput * widthOutput * sizeof(double));
    

But to me all of it looks kind of complicated, simply it would looks like

void transposeMatrix(double* src, double* dst, int n, int m)
{
    int i, j;
    for(i = 0; i < n; ++i)
        for(j = 0; j < m; ++j)
            dst[j * n + i] = src[i * m + j];
}

int main(void)
{
    double array[2][3] = {{1,2,3},{4,5,6}};
    int height = 2;
    int width = 3;
    int i, j;

    double *output = malloc(height * width * sizeof(double));

    printf("input matrix\n");
    for(i=0;i<height;i++)
    {
        for(j=0;j<width;j++)
        {
            printf("%f\t",array[i][j]);
        }
        printf("\n");
    }

    transposeMatrix(&array[0][0], output, height,width);

    printf("output matrix\n");
    for(i=0;i<width;i++)
    {
        for(j=0;j<height;j++)
        {
            printf("%f\t",output[i*height + j]);
        }
        printf("\n");
    }
}

Edit: To answer to your comment: Let' say we have matrix 4 * 5

| a00 a01 a02 a03 a04 |
| a10 a11 a12 a13 a14 |
| a20 a21 a22 a23 a24 |
| a30 a31 a32 a33 a34 |

In memory allocated with

// n = 4, m = 5
double* A = malloc(n * m * sizeof(double));

it will look like

| a00 a01 a02 a03 a04 a10 a11 a12 a13 a14 a20 a21 a22 a23 a24 a30 a31 a32 a33 a34 |

So to get element let's say (2, 3) we need to skip 2 * 5 elements (it's two rows each of 5 elements) and 3 elements from the beginning of the third row, so - 13 elements to skip in array. And to generalize for matrix m * n to get (i, j) element we need to skip (i * m) + j elements in array.

like image 152
Nikolay K Avatar answered Nov 15 '22 09:11

Nikolay K