使用指针的C矩阵乘法

时间:2014-09-11 17:33:41

标签: c pointers matrix

嘿大家所以我正在使用指针制作矩阵乘数我已经撞到了墙。到目前为止,我已经做到了,现在已经遇到了障碍。

我的问题:在生成尺寸3x3或更大(2x2和1x1返回正确值)的矩阵时,生成的矩阵返回的值太大。

这是已编辑的代码:

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

    void main() {
        int i, j, k, m, n, p, q, m1_rows, m1_cols, m2_rows, m2_cols, mr_rows, mr_cols;
        double **m1, **m2, **mr;
        printf("Enter number of rows and columns of 1st matrix:");
        scanf("%d%d",&m,&n);
        printf("Enter number of rows and columns of 2nd matrix:");
        scanf("%d%d",&p,&q);

        if(n!=p) printf("Not possible");
        else {
        m1 = malloc(sizeof(double *) * m1_rows);
        for(int i=0; i < m1_rows; i++) m1[i] = malloc(sizeof(double) * m1_cols);

        m2 = malloc(sizeof(double *) * m2_rows);
        for(int i=0; i < m2_rows; i++) m2[i] = malloc(sizeof(double) * m2_cols);

        mr = malloc(sizeof(double *) * mr_rows);
        for(int i=0; i < mr_rows; i++) mr[i] = malloc(sizeof(double) * mr_cols);

        printf("Enter 1st matrix values:");
        for(i=0;i<m1_rows;i++) {
            for(j=0;j<m1_cols;j++) {
                scanf("%d",(&m1[i][j]));
            }
        }

        printf("Enter 2nd matrix values:\n");
        for(i=0;i<m2_rows;i++) for(j=0;j<m2_cols;j++) scanf("%d",(*(m2+i)+j));

        printf("First matrix is:\n");
        for(i=0;i<m1_rows;i++) {
            printf("\n");
            for(j=0;j<m1_cols;j++) printf("%d\t",*(*(m1+i)+j)); }

        printf("\nSecond matrix is:\n");
        for(i=0;i<m2_rows;i++) {
            printf("\n");
            for(j=0;j<m2_cols;j++) printf("%d\t",*(*(m2+i)+j)); }

        for(i=0;i<m1_rows;i++) {
            for(j=0;j<m2_cols;j++) {
                *(*(mr+i)+j) = 0;
            }
        }
    }
    getch();
    return 0;
    }

4 个答案:

答案 0 :(得分:1)

主要问题是您尝试仅使用单个维度分配二维数据结构,但仍使用二维类型(指向指针的指针)。如果您更改代码以使用数组索引语法,例如

,那么您是多么错误
*(m1+i)+j

将是

&m1[i][j]

使用数组索引语法,您应该看到您实际上没有分配第二个维度。你为它分配了空间,但它根本不起作用,因为二维数组的内存布局与使用指针指针的二维数组的布局不同。


为了进一步解释数组数组(所有数据都在一个连续的块中)和指向指针的指针之间的区别,请参见下图:

例如声明

double a[2][2];

内存布局为

+---------+---------+---------+---------+
| a[0][0] | a[0][1] | a[1][0] | a[1][1] |
+---------+---------+---------+---------+

但如果你使用例如指向指针的指针:

double **a;

然后经过适当的分配,它看起来像这个

+------+------+-----+
| a[0] | a[1] | ... |
+------+------+-----+
  |      |
  |      V
  |      +---------+---------+-----+
  |      | a[1][0] | a[1][1] | ... |
  |      +---------+---------+-----+
  V
  +---------+---------+-----+
  | a[0][0] | a[0][1] | ... |
  +---------+---------+-----+

希望您现在应该了解为什么,在您的情况下,m1[x](对于任何x)会导致undefined behavior,因为它是未初始化的指针。


这个问题的简单解决方案?只需做两个分配:一个用于&#34;行&#34;一个用于&#34;列&#34;。

m1 = malloc(sizeof(double *) * m1_rows);
for (int i = 0; i < m1_rows; ++i)
    m1[i] = malloc(sizeof(double) * m1_columns);

答案 1 :(得分:0)

首先:

  • 打印double使用%f%d适用于int
  • 使用double使用%lf进行扫描。 %d适用于int

答案 2 :(得分:0)

1)变量m1_rowsm1_colsm2_rowsm2_colsmr_rowsmr_cols未初始化,但您使用它在内存分配期间。

2)对于双数据类型,请使用%f%lf%d用于int。

3)您没有执行任何矩阵乘法,因此需要执行矩阵乘法并打印结果。

4)为指针分配内存后,不要忘记释放指针。

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

int main() 
{
    int i, j, k, m, n, p, q, m1_rows, m1_cols, m2_rows, m2_cols, mr_rows, mr_cols;
    double **m1, **m2, **mr;
    printf("Enter number of rows and columns of 1st matrix:");
    scanf("%d%d",&m,&n);
    printf("Enter number of rows and columns of 2nd matrix:");
    scanf("%d%d",&p,&q);
    // m1_rows, m1_cols, m2_rows, m2_cols, mr_rows and mr_cols are not initialized, however you are using it during memory allocation
    m1_rows = m;
    m1_cols = n;
    m2_rows = p;
    m2_cols = q;
    mr_rows = m;
    mr_cols = q;

    if(n!=p) printf("Not possible");
    else 
    {
        m1 = malloc(sizeof(double *) * m1_rows);
        for(i=0; i < m1_rows; i++) m1[i] = malloc(sizeof(double) * m1_cols);

        m2 = malloc(sizeof(double *) * m2_rows);
        for(i=0; i < m2_rows; i++) m2[i] = malloc(sizeof(double) * m2_cols);

        mr = malloc(sizeof(double *) * mr_rows);
        for(i=0; i < mr_rows; i++) mr[i] = malloc(sizeof(double) * mr_cols);

        printf("Enter 1st matrix values:");
        for(i=0;i<m1_rows;i++) 
        {
            for(j=0;j<m1_cols;j++) 
            {
                scanf("%lf",&m1[i][j]);
            }
        }

        printf("Enter 2nd matrix values:\n");
        for(i=0;i<m2_rows;i++) 
        {
            for(j=0;j<m2_cols;j++)
            {
                scanf("%lf",&m2[i][j]);
            }
        }

        printf("First matrix is:\n");
        for(i=0;i<m1_rows;i++) 
        {
            printf("\n");
            for(j=0;j<m1_cols;j++)
            {
                printf("%.2lf\t",*(*(m1+i)+j)); 
            }
        }

        printf("\nSecond matrix is:\n");
        for(i=0;i<m2_rows;i++) 
        {
            printf("\n");
            for(j=0;j<m2_cols;j++)
            {
                printf("%.2lf\t",*(*(m2+i)+j)); 
            }
        }
        //Matrix multiplication
        for(i=0;i<m1_rows;i++) 
        {
            for(j=0;j<m2_cols;j++) 
            {
                mr[i][j] = 0;
                for(k=0;k<m1_cols;k++)
                {
                    mr[i][j] = mr[i][j]+m1[i][k] * m2[k][j];
                }
            }
        }
        //Print the result
        printf("\nResult matrix is:\n");
        for(i=0;i<mr_rows;i++) 
        {
            printf("\n");
            for(j=0;j<mr_cols;j++)
            {
                printf("%.2lf\t",mr[i][j]); 
            }
        }
        //Free the allocated memory
        for(i=0;i<m1_rows;i++)
        {
            free(m1[i]);
        }
        free(m1);
        for(i=0;i<m2_rows;i++)
        {
            free(m2[i]);
        }
        free(m2);
        for(i=0;i<mr_rows;i++)
        {
            free(mr[i]);
        }
        free(mr);
    }
    printf("\n");
    return 0;
}

答案 3 :(得分:0)

这是一个快速尝试,展示了实现逻辑的方法。正如评论中所示,一个问题是代码中无数的单元化变量。如果可能,请勿以不同的名称复制变量 - 这只会打开其他可能的错误。如果您有疑问,请告诉我。 (我保留了你的指针等价:m1[i][j] = *(*(m1+i)+j)只是为了表明它们是可以互换的):

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

int main () {

    int c, i = 0, j = 0, m = 0, n = 0, p = 0, q = 0;
    double **m1, **m2, **mr;

    printf ("Enter number of rows and columns of 1st matrix: ");
    scanf ("%d %d", &m, &n);
    do { c = getchar (); } while (c != '\n' && c != EOF);   /* flush input buffer */

    printf ("Enter number of rows and columns of 2nd matrix: ");
    scanf ("%d %d", &p, &q);
    do { c = getchar (); } while (c != '\n' && c != EOF);   /* flush input buffer */

    if (n != p)
        printf ("Not possible\n");
    else {
        m1 = malloc (sizeof (double *) * m);
        for (int i = 0; i < m; i++)
            m1[i] = calloc (n, sizeof (double));    /* use calloc to 0 elements */

        m2 = malloc (sizeof (double *) * p);
        for (int i = 0; i < p; i++)
            m2[i] = calloc (q, sizeof (double));    /* use calloc to 0 elements */

        mr = malloc (sizeof (double *) * m);
        for (int i = 0; i < m; i++)
            mr[i] = calloc (q, sizeof (double));    /* use calloc to 0 elements */

        printf ("Enter 1st matrix values:\n");
        for (i = 0; i < m; i++) {
            for (j = 0; j < n; j++) {
                printf ("  m1[%d][%d]: ", i, j);
                scanf ("%lf", &m1[i][j]);
                do { c = getchar (); } while (c != '\n' && c != EOF);   /* flush input buffer */
            }
        }

        printf ("Enter 2nd matrix values:\n");
        for (i = 0; i < p; i++)
            for (j = 0; j < q; j++) {
                printf ("  m1[%d][%d]: ", i, j);
                scanf ("%lf", &(*(*(m2 + i))));
                do { c = getchar (); } while (c != '\n' && c != EOF);   /* flush input buffer */
            }

        printf ("\nFirst matrix is:\n");
        for (i = 0; i < m; i++) {
            printf ("\n");
            for (j = 0; j < n; j++)
                printf ("%lf\t", *(*(m1 + i) + j));
        }

        printf ("\n\nSecond matrix is:\n");
        for (i = 0; i < p; i++) {
            printf ("\n");
            for (j = 0; j < q; j++)
                printf ("%lf\t", *(*(m2 + i) + j));
        }

        printf ("\n");

        /* THIS FREES NOTHING - allocate with calloc or use memset to 0 */
//         for(i=0;i<m;i++) {
//             for(j=0;j<q;j++) {
//                 *(*(mr+i)+j) = 0;
//             }
//         }


        printf ("\nFree First matrix\n");
        for (i = 0; i < m; i++) {
            if (*(m1 + i))
                free (*(m1 + i));
        }
        if (m1)
            free (m1);

        printf ("Free Second matrix\n");
        for (i = 0; i < p; i++) {
            if (*(m2 + i))
                free (*(m2 + i));
        }
        if (m2)
            free (m2);

        printf ("Free Result matrix\n\n");
        for (i = 0; i < m; i++) {
            if (*(mr + i))
                free (*(mr + i));
        }
        if (mr)
            free (mr);
    }

    return 0;
}

<强>构建

注意:始终至少使用-Wall -Wextra进行构建,以识别代码中的问题。

gcc -Wall -Wextra -Wno-sign-compare -Wno-long-long -std=c99 -o bin/badmtrx badmtrx.c 

<强>输出:

$ ./bin/badmtrx
Enter number of rows and columns of 1st matrix: 1 3
Enter number of rows and columns of 2nd matrix: 3 1
Enter 1st matrix values:
    m1[0][0]: 1
    m1[0][1]: 2
    m1[0][2]: 3
Enter 2nd matrix values:
    m1[0][0]: 4
    m1[1][0]: 5
    m1[2][0]: 6

First matrix is:

1.000000        2.000000        3.000000

Second matrix is:

4.000000
5.000000
6.000000

Free First matrix
Free Second matrix
Free Result matrix

valgrind堆摘要:

==10711== HEAP SUMMARY:
==10711==     in use at exit: 0 bytes in 0 blocks
==10711==   total heap usage: 8 allocs, 8 frees, 96 bytes allocated
==10711==
==10711== All heap blocks were freed -- no leaks are possible
==10711==
==10711== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
--10711--
--10711-- used_suppression:      2 dl-hack3-cond-1
==10711==
==10711== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)