如何在C语言中转置矩阵? - 错误

7
我将尝试编写一个函数来转置矩阵。
该函数的参数如下:
- 需要转置的矩阵 - 空的输出矩阵
问题是,我能够转置一些矩阵,但有些矩阵会失败,就像我在示例中提供的那个。为什么?我该如何解决?
代码:
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");
    }


}

1
当要求他人阅读您的代码时,请使用空格。像这样:result = (*((array2 + i * width) + j)); 这会让我们更容易理解。 - Almo
2个回答

3
主要问题在于您混淆了矩阵的大小。
  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));
    
但对我来说,这一切看起来有些复杂,简单来说就像这样。
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");
    }
}

编辑: 回复您的评论:假设我们有一个4 * 5的矩阵

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

在使用分配内存时

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

它将看起来像:

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

要获取元素 (2, 3),我们需要跳过 2 * 5 个元素(即两行每行有 5 个元素),并跳过第三行开头的 3 个元素,因此在数组中需要跳过 13 个元素。 对于矩阵 m * n 中的任意元素 (i, j),我们需要跳过 (i * m) + j 个元素。


你好,非常感谢,这个有效了。 能否提供一些关于这个符号的信息/它输出[i*height + j]是做什么用的? - LandonZeKepitelOfGreytBritn
@trilolil 这与 *((output+i*height)+j)) 相同。当您线性分配矩阵内存时,如 double* A = malloc(n*m*sizeof(double)),您可以使用 A[i*m+j] 访问 (i, j) 元素。 - Nikolay K
但我不明白的是,为什么你需要这个乘法? - LandonZeKepitelOfGreytBritn

0
include stdio.h  
include conio.h 
include string.h
include stdlib.h

int main(){

    int i,j,n,t=0,a[100][100],k,l,b=0;

    printf(" n="); // you write the number or rows and columns or the matrix
    scanf("%d",&n);

    for(i=1;i<=n;i++){ //you write the elements of the matrix
        for(j=1;j<=n;j++){
            printf("a[%d][%d]=",i,j);
            scanf("%d",&a[i][j]);
        }
    }
    printf("\n");

    for(i=1;i<=n;i++){ //you can see you original matrix
        for(j=1;j<=n;j++){
            printf("%d ",a[i][j]);
        } 
        printf("\n");
    }
    printf("\n -\n");

    for (i=2; i<=n; i++) { //now we transpose the original matrix
        for (j=1; j < i; j++) {
            t = a[i][j];
            a[i][j] = a[j][i];
            a[j][i] = t;
            printf("\n da \n");
         }
   }

// 现在我们可以看到矩阵的转置

// 并将其与第一个进行比较

printf("\n  \n ");

for(i=1;i<=n;i++){ 
    for(j=1;j<=n;j++){
        printf("%d ",a[i][j]);
    }
    printf("\n");
}
printf("\n  \n");

system("PAUSE");

return 0;

1
欢迎来到 Stack Overflow。除了提供代码示例外,用英语解释您的解决方案会很有帮助。 - Matt Raines
欢迎来到SO,并进一步扩展@MattRaines的评论,请仔细检查您代码的格式。 - Richard Erickson
感谢您的热情欢迎 :) - Kiva

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接